Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19691545 | 235 days ago | 0.51437807 ETH | ||||
19691545 | 235 days ago | 0.51437807 ETH | ||||
10878892 | 1546 days ago | 1 wei | ||||
10878892 | 1546 days ago | 1 wei | ||||
10860064 | 1549 days ago | 1.24856005 ETH | ||||
10860064 | 1549 days ago | 1.24856005 ETH | ||||
10601328 | 1588 days ago | 0.75 ETH | ||||
10601328 | 1588 days ago | 0.75 ETH | ||||
10503497 | 1604 days ago | 29.1 ETH | ||||
10503497 | 1604 days ago | 29.1 ETH | ||||
10408516 | 1618 days ago | 4 ETH | ||||
10408516 | 1618 days ago | 4 ETH | ||||
10408504 | 1618 days ago | 2 ETH | ||||
10408504 | 1618 days ago | 2 ETH | ||||
10408481 | 1618 days ago | 4 ETH | ||||
10408481 | 1618 days ago | 4 ETH | ||||
10395176 | 1620 days ago | 0.85784865 ETH | ||||
10395176 | 1620 days ago | 0.85784865 ETH | ||||
10394766 | 1620 days ago | 1.72727195 ETH | ||||
10394766 | 1620 days ago | 1.72727195 ETH | ||||
10394766 | 1620 days ago | 1.72727195 ETH | ||||
10394766 | 1620 days ago | 1.72727195 ETH | ||||
10393276 | 1621 days ago | 13.974 ETH | ||||
10393276 | 1621 days ago | 13.974 ETH | ||||
10392203 | 1621 days ago | 0.1 ETH |
Loading...
Loading
Contract Name:
OneSplit
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-06-26 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/IOneSplit.sol pragma solidity ^0.5.0; // // [ msg.sender ] // | | // | | // \_/ // +---------------+ ________________________________ // | OneSplitAudit | _______________________________ \ // +---------------+ \ \ // | | ______________ | | (staticcall) // | | / ____________ \ | | // | | (call) / / \ \ | | // | | / / | | | | // \_/ | | \_/ \_/ // +--------------+ | | +----------------------+ // | OneSplitWrap | | | | OneSplitViewWrap | // +--------------+ | | +----------------------+ // | | | | | | // | | (delegatecall) | | (staticcall) | | (staticcall) // \_/ | | \_/ // +--------------+ | | +------------------+ // | OneSplit | | | | OneSplitView | // +--------------+ | | +------------------+ // | | / / // \ \________________/ / // \__________________/ // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_KYBER + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01; uint256 internal constant FLAG_DISABLE_KYBER = 0x02; uint256 internal constant FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x100000000; // Turned off by default uint256 internal constant FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x200000000; // Turned off by default uint256 internal constant FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x400000000; // Turned off by default uint256 internal constant FLAG_DISABLE_BANCOR = 0x04; uint256 internal constant FLAG_DISABLE_OASIS = 0x08; uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10; uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20; uint256 internal constant FLAG_DISABLE_CHAI = 0x40; uint256 internal constant FLAG_DISABLE_AAVE = 0x80; uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 internal constant FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Turned off by default uint256 internal constant FLAG_DISABLE_BDAI = 0x400; uint256 internal constant FLAG_DISABLE_IEARN = 0x800; uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 internal constant FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Turned off by default uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 internal constant FLAG_DISABLE_WETH = 0x80000; uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_IDLE = 0x800000; uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000; uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000; uint256 internal constant FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Turned off by default uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000; uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000; uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000; uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000; uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000; uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000; } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/interface/IUniswapExchange.sol pragma solidity ^0.5.0; interface IUniswapExchange { function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought); function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought); function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256 tokensBought); function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); } // File: contracts/interface/IKyberNetworkContract.sol pragma solidity ^0.5.0; interface IKyberNetworkContract { function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless) external view returns (address reserve, uint256 rate); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity ^0.5.0; interface IKyberNetworkProxy { function getExpectedRate(IERC20 src, IERC20 dest, uint256 srcQty) external view returns (uint256 expectedRate, uint256 slippageRate); function tradeWithHint( IERC20 src, uint256 srcAmount, IERC20 dest, address destAddress, uint256 maxDestAmount, uint256 minConversionRate, address walletId, bytes calldata hint ) external payable returns (uint256); function kyberNetworkContract() external view returns (IKyberNetworkContract); // TODO: Limit usage by tx.gasPrice // function maxGasPrice() external view returns (uint256); // TODO: Limit usage by user cap // function getUserCapInWei(address user) external view returns (uint256); // function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256); } // File: contracts/interface/IKyberUniswapReserve.sol pragma solidity ^0.5.0; interface IKyberUniswapReserve { function uniswapFactory() external view returns (address); } // File: contracts/interface/IKyberOasisReserve.sol pragma solidity ^0.5.0; interface IKyberOasisReserve { function otc() external view returns (address); } // File: contracts/interface/IKyberBancorReserve.sol pragma solidity ^0.5.0; contract IKyberBancorReserve { function bancorEth() public view returns (address); } // File: contracts/interface/IBancorNetwork.sol pragma solidity ^0.5.0; interface IBancorNetwork { function getReturnByPath(address[] calldata path, uint256 amount) external view returns (uint256 returnAmount, uint256 conversionFee); function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn) external returns (uint256); function convert(address[] calldata path, uint256 amount, uint256 minReturn) external payable returns (uint256); } // File: contracts/interface/IBancorContractRegistry.sol pragma solidity ^0.5.0; contract IBancorContractRegistry { function addressOf(bytes32 contractName) external view returns (address); } // File: contracts/interface/IBancorConverterRegistry.sol pragma solidity ^0.5.0; interface IBancorConverterRegistry { function getConvertibleTokenSmartTokenCount(IERC20 convertibleToken) external view returns(uint256); function getConvertibleTokenSmartTokens(IERC20 convertibleToken) external view returns(address[] memory); function getConvertibleTokenSmartToken(IERC20 convertibleToken, uint256 index) external view returns(address); function isConvertibleTokenSmartToken(IERC20 convertibleToken, address value) external view returns(bool); } // File: contracts/interface/IBancorEtherToken.sol pragma solidity ^0.5.0; contract IBancorEtherToken is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/IOasisExchange.sol pragma solidity ^0.5.0; interface IOasisExchange { function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt) external view returns (uint256 fillAmt); function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount) external returns (uint256 fillAmt); } // File: contracts/interface/IWETH.sol pragma solidity ^0.5.0; contract IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/ICurve.sol pragma solidity ^0.5.0; interface ICurve { // solium-disable-next-line mixedcase function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external; // solium-disable-next-line mixedcase function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external; } // File: contracts/interface/IChai.sol pragma solidity ^0.5.0; interface IPot { function dsr() external view returns (uint256); function chi() external view returns (uint256); function rho() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } contract IChai is IERC20 { function POT() public view returns (IPot); function join(address dst, uint256 wad) external; function exit(address src, uint256 wad) external; } library ChaiHelper { IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7); uint256 private constant RAY = 10**27; function _mul(uint256 x, uint256 y) private pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, y) / RAY; } function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, RAY) / y; } function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) { // solium-disable-next-line security/no-inline-assembly assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } function potDrip() private view returns (uint256) { return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi()); } function chaiPrice(IChai chai) internal view returns(uint256) { return chaiToDai(chai, 1e18); } function daiToChai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rdiv(amount, chi); } function chaiToDai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rmul(chi, amount); } } // File: contracts/interface/ICompound.sol pragma solidity ^0.5.0; contract ICompound { function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa); } contract ICompoundToken is IERC20 { function underlying() external view returns (address); function exchangeRateStored() external view returns (uint256); function mint(uint256 mintAmount) external returns (uint256); function redeem(uint256 redeemTokens) external returns (uint256); } contract ICompoundEther is IERC20 { function mint() external payable; function redeem(uint256 redeemTokens) external returns (uint256); } // File: contracts/interface/IAaveToken.sol pragma solidity ^0.5.0; contract IAaveToken is IERC20 { function underlyingAssetAddress() external view returns (IERC20); function redeem(uint256 amount) external; } interface IAaveLendingPool { function core() external view returns (address); function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable; } // File: contracts/interface/IMooniswap.sol pragma solidity ^0.5.0; interface IMooniswapRegistry { function target() external view returns(IMooniswap); } interface IMooniswap { function getReturn( IERC20 fromToken, IERC20 destToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn ) external payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/UniversalERC20.sol pragma solidity ^0.5.0; library UniversalERC20 { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) { if (amount == 0) { return true; } if (isETH(token)) { address(uint160(to)).transfer(amount); } else { token.safeTransfer(to, amount); return true; } } function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()"); if (to != address(this)) { address(uint160(to)).transfer(amount); } if (msg.value > amount) { msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(from, to, amount); } } function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { if (msg.value > amount) { // Return remainder if exist msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(msg.sender, address(this), amount); } } function universalApprove(IERC20 token, address to, uint256 amount) internal { if (!isETH(token)) { if (amount == 0) { token.safeApprove(to, 0); return; } uint256 allowance = token.allowance(address(this), to); if (allowance < amount) { if (allowance > 0) { token.safeApprove(to, 0); } token.safeApprove(to, amount); } } } function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); } } function universalDecimals(IERC20 token) internal view returns (uint256) { if (isETH(token)) { return 18; } (bool success, bytes memory data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("decimals()") ); if (!success || data.length == 0) { (success, data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("DECIMALS()") ); } return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18; } function isETH(IERC20 token) internal pure returns(bool) { return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS)); } function notExist(IERC20 token) internal pure returns(bool) { return (address(token) == address(-1)); } } // File: contracts/interface/IUniswapV2Exchange.sol pragma solidity ^0.5.0; interface IUniswapV2Exchange { function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; } library UniswapV2ExchangeLib { using SafeMath for uint256; using UniversalERC20 for IERC20; function getReturn( IUniswapV2Exchange exchange, IERC20 fromToken, IERC20 destToken, uint amountIn ) internal view returns (uint256) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = destToken.universalBalanceOf(address(exchange)); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); return (denominator == 0) ? 0 : numerator.div(denominator); } } // File: contracts/interface/IUniswapV2Factory.sol pragma solidity ^0.5.0; interface IUniswapV2Factory { function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair); } // File: contracts/interface/IDForceSwap.sol pragma solidity ^0.5.0; interface IDForceSwap { function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256); function swap(IERC20 input, IERC20 output, uint256 amount) external; } // File: contracts/interface/IShell.sol pragma solidity ^0.5.0; interface IShell { function viewOriginTrade( address origin, address target, uint256 originAmount ) external view returns (uint256); function swapByOrigin( address origin, address target, uint256 originAmount, uint256 minTargetAmount, uint256 deadline ) external returns (uint256); } // File: contracts/interface/IMStable.sol pragma solidity ^0.5.0; contract IMStable is IERC20 { function getSwapOutput( IERC20 _input, IERC20 _output, uint256 _quantity ) external view returns (bool, string memory, uint256 output); function swap( IERC20 _input, IERC20 _output, uint256 _quantity, address _recipient ) external returns (uint256 output); function redeem( IERC20 _basset, uint256 _bassetQuantity ) external returns (uint256 massetRedeemed); } interface IMassetRedemptionValidator { function getRedeemValidity( IERC20 _mAsset, uint256 _mAssetQuantity, IERC20 _outputBasset ) external view returns (bool, string memory, uint256 output); } // File: contracts/interface/IBalancerRegistry.sol pragma solidity ^0.5.0; interface IBalancerPool { function swapExactAmountIn( IERC20 tokenIn, uint256 tokenAmountIn, IERC20 tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter); } pragma solidity ^0.5.0; interface IBalancerRegistry { event PoolAdded( address indexed pool ); event PoolTokenPairAdded( address indexed pool, address indexed fromToken, address indexed destToken ); event IndicesUpdated( address indexed fromToken, address indexed destToken, bytes32 oldIndices, bytes32 newIndices ); // Get info about pool pair for 1 SLOAD function getPairInfo(address pool, address fromToken, address destToken) external view returns(uint256 weight1, uint256 weight2, uint256 swapFee); // Pools function checkAddedPools(address pool) external view returns(bool); function getAddedPoolsLength() external view returns(uint256); function getAddedPools() external view returns(address[] memory); function getAddedPoolsWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Tokens function getAllTokensLength() external view returns(uint256); function getAllTokens() external view returns(address[] memory); function getAllTokensWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Pairs function getPoolsLength(address fromToken, address destToken) external view returns(uint256); function getPools(address fromToken, address destToken) external view returns(address[] memory); function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit) external view returns(address[] memory result); function getBestPools(address fromToken, address destToken) external view returns(address[] memory pools); function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit) external view returns(address[] memory pools); // Get swap rates function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount) external view returns(uint256); function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts) external view returns(uint256[] memory result); // Add and update registry function addPool(address pool) external returns(uint256 listed); function addPools(address[] calldata pools) external returns(uint256[] memory listed); function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external; } // File: contracts/OneSplitBase.sol pragma solidity ^0.5.0; //import "./interface/IBancorNetworkPathFinder.sol"; contract IOneSplitView is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns(bool) { return (flags & flag) != 0; } } contract OneSplitRoot is IOneSplitView { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20; using UniversalERC20 for IWETH; using UniswapV2ExchangeLib for IUniswapV2Exchange; using ChaiHelper for IChai; uint256 constant internal DEXES_COUNT = 27; IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant internal bnt = IERC20(0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C); IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D); IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847); IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380); IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6); IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x818E6FECD516Ecc3849DAf6845e3EC868087B755); IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); //IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); //IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D); ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); ICurve constant internal curveRenBTC = ICurve(0x8474c1236F0Bc23830A23a41aBB81B2764bA9f4F); ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E); ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714); IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D); IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0x7079E8517594e5b21d2B9a0D17cb33F5FE2bca70); IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2); IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5); IMassetRedemptionValidator constant internal musd_helper = IMassetRedemptionValidator(0x4c5e03065bC52cCe84F3ac94DF14bbAC27eac89b); IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982); int256 internal constant VERY_NEGATIVE_VALUE = -1e72; function _findBestDistribution( uint256 s, // parts int256[][] memory amounts // exchangesReturns ) internal pure returns( int256 returnAmount, uint256[] memory distribution ) { uint256 n = amounts.length; int256[][] memory answer = new int256[][](n); // int[n][s+1] uint256[][] memory parent = new uint256[][](n); // int[n][s+1] for (uint i = 0; i < n; i++) { answer[i] = new int256[](s + 1); parent[i] = new uint256[](s + 1); } for (uint j = 0; j <= s; j++) { answer[0][j] = amounts[0][j]; for (uint i = 1; i < n; i++) { answer[i][j] = -1e72; } parent[0][j] = 0; } for (uint i = 1; i < n; i++) { for (uint j = 0; j <= s; j++) { answer[i][j] = answer[i - 1][j]; parent[i][j] = j; for (uint k = 1; k <= j; k++) { if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) { answer[i][j] = answer[i - 1][j - k] + amounts[i][k]; parent[i][j] = j - k; } } } } distribution = new uint256[](DEXES_COUNT); uint256 partsLeft = s; for (uint curExchange = n - 1; partsLeft > 0; curExchange--) { distribution[curExchange] = partsLeft - parent[curExchange][partsLeft]; partsLeft = parent[curExchange][partsLeft]; } returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s]; } function _buildBancorPath( IERC20 fromToken, IERC20 destToken ) internal view returns(address[] memory path) { if (fromToken == destToken) { return new address[](0); } if (fromToken.isETH()) { fromToken = ETH_ADDRESS; } if (destToken.isETH()) { destToken = ETH_ADDRESS; } if (fromToken == bnt || destToken == bnt) { path = new address[](3); } else { path = new address[](5); } address fromConverter; address toConverter; IBancorConverterRegistry bancorConverterRegistry = IBancorConverterRegistry(bancorContractRegistry.addressOf("BancorConverterRegistry")); if (fromToken != bnt) { (bool success, bytes memory data) = address(bancorConverterRegistry).staticcall.gas(100000)(abi.encodeWithSelector( bancorConverterRegistry.getConvertibleTokenSmartToken.selector, fromToken.isETH() ? ETH_ADDRESS : fromToken, 0 )); if (!success) { return new address[](0); } fromConverter = abi.decode(data, (address)); if (fromConverter == address(0)) { return new address[](0); } } if (destToken != bnt) { (bool success, bytes memory data) = address(bancorConverterRegistry).staticcall.gas(100000)(abi.encodeWithSelector( bancorConverterRegistry.getConvertibleTokenSmartToken.selector, destToken.isETH() ? ETH_ADDRESS : destToken, 0 )); if (!success) { return new address[](0); } toConverter = abi.decode(data, (address)); if (toConverter == address(0)) { return new address[](0); } } if (destToken == bnt) { path[0] = address(fromToken); path[1] = fromConverter; path[2] = address(bnt); return path; } if (fromToken == bnt) { path[0] = address(bnt); path[1] = toConverter; path[2] = address(destToken); return path; } path[0] = address(fromToken); path[1] = fromConverter; path[2] = address(bnt); path[3] = toConverter; path[4] = address(destToken); return path; } function _getCompoundToken(IERC20 token) internal pure returns(ICompoundToken) { if (token.isETH()) { // ETH return ICompoundToken(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); } if (token == IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { // DAI return ICompoundToken(0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643); } if (token == IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF)) { // BAT return ICompoundToken(0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E); } if (token == IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862)) { // REP return ICompoundToken(0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1); } if (token == IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { // USDC return ICompoundToken(0x39AA39c021dfbaE8faC545936693aC917d5E7563); } if (token == IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)) { // WBTC return ICompoundToken(0xC11b1268C1A384e55C48c2391d8d480264A3A7F4); } if (token == IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498)) { // ZRX return ICompoundToken(0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407); } if (token == IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { // USDT return ICompoundToken(0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9); } return ICompoundToken(0); } function _getAaveToken(IERC20 token) internal pure returns(IAaveToken) { if (token.isETH()) { // ETH return IAaveToken(0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04); } if (token == IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { // DAI return IAaveToken(0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d); } if (token == IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { // USDC return IAaveToken(0x9bA00D6856a4eDF4665BcA2C2309936572473B7E); } if (token == IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51)) { // SUSD return IAaveToken(0x625aE63000f46200499120B906716420bd059240); } if (token == IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53)) { // BUSD return IAaveToken(0x6Ee0f7BB50a54AB5253dA0667B0Dc2ee526C30a8); } if (token == IERC20(0x0000000000085d4780B73119b644AE5ecd22b376)) { // TUSD return IAaveToken(0x4DA9b813057D04BAef4e5800E36083717b4a0341); } if (token == IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { // USDT return IAaveToken(0x71fc860F7D3A592A4a98740e39dB31d25db65ae8); } if (token == IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF)) { // BAT return IAaveToken(0xE1BA0FB44CCb0D11b80F92f4f8Ed94CA3fF51D00); } if (token == IERC20(0xdd974D5C2e2928deA5F71b9825b8b646686BD200)) { // KNC return IAaveToken(0x9D91BE44C06d373a8a226E1f3b146956083803eB); } if (token == IERC20(0x80fB784B7eD66730e8b1DBd9820aFD29931aab03)) { // LEND return IAaveToken(0x7D2D3688Df45Ce7C552E19c27e007673da9204B8); } if (token == IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA)) { // LINK return IAaveToken(0xA64BD6C70Cb9051F6A9ba1F163Fdc07E0DfB5F84); } if (token == IERC20(0x0F5D2fB29fb7d3CFeE444a200298f468908cC942)) { // MANA return IAaveToken(0x6FCE4A401B6B80ACe52baAefE4421Bd188e76F6f); } if (token == IERC20(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2)) { // MKR return IAaveToken(0x7deB5e830be29F91E298ba5FF1356BB7f8146998); } if (token == IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862)) { // REP return IAaveToken(0x71010A9D003445aC60C4e6A7017c1E89A477B438); } if (token == IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F)) { // SNX return IAaveToken(0x328C4c80BC7aCa0834Db37e6600A6c49E12Da4DE); } if (token == IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)) { // WBTC return IAaveToken(0xFC4B8ED459e00e5400be803A9BB3954234FD50e3); } if (token == IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498)) { // ZRX return IAaveToken(0x6Fb0855c404E09c47C3fBCA25f08d4E41f9F062f); } return IAaveToken(0); } function _scaleDestTokenEthPriceTimesGasPrice( IERC20 fromToken, IERC20 destToken, uint256 destTokenEthPriceTimesGasPrice ) internal view returns(uint256) { uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 1e16); uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 1e16); if (div > 0) { return destTokenEthPriceTimesGasPrice.mul(mul).div(div); } return 0; } function _cheapGetPrice( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal view returns(uint256 returnAmount) { (returnAmount,,) = this.getExpectedReturnWithGas( fromToken, destToken, amount, 1, FLAG_DISABLE_SPLIT_RECALCULATION | FLAG_DISABLE_ALL_SPLIT_SOURCES | FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP, 0 ); } function _linearInterpolation( uint256 value, uint256 parts ) internal pure returns(uint256[] memory rets) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) { return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB); } } contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = this.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _getExpectedReturnRespectingGasFloor( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } contract OneSplitView is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); if (fromToken == destToken) { return (amount, 0, distribution); } function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags); int256[][] memory matrix = new int256[][](DEXES_COUNT); uint256[DEXES_COUNT] memory gases; bool atLeastOnePositive = false; for (uint i = 0; i < DEXES_COUNT; i++) { uint256[] memory rets; (rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags); // Prepend zero and sub gas int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18)); matrix[i] = new int256[](parts + 1); for (uint j = 0; j < parts; j++) { matrix[i][j + 1] = int256(rets[j]) - gas; atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0); } } if (!atLeastOnePositive) { for (uint i = 0; i < DEXES_COUNT; i++) { for (uint j = 1; j < parts + 1; j++) { if (matrix[i][j] == 0) { matrix[i][j] = VERY_NEGATIVE_VALUE; } } } } (, distribution) = _findBestDistribution(parts, matrix); (returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution( Args({ fromToken: fromToken, destToken: destToken, amount: amount, parts: parts, flags: flags, destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice, distribution: distribution, matrix: matrix, gases: gases, reserves: reserves }) ); return (returnAmount, estimateGasAmount, distribution); } struct Args { IERC20 fromToken; IERC20 destToken; uint256 amount; uint256 parts; uint256 flags; uint256 destTokenEthPriceTimesGasPrice; uint256[] distribution; int256[][] matrix; uint256[DEXES_COUNT] gases; function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] reserves; } function _getReturnAndGasByDistribution( Args memory args ) internal view returns(uint256 returnAmount, uint256 estimateGasAmount) { bool[DEXES_COUNT] memory exact = [ true, // "Uniswap", false, // "Kyber", false, // "Bancor", false, // "Oasis", false, // "Curve Compound", false, // "Curve USDT", false, // "Curve Y", false, // "Curve Binance", false, // "CurveSynthetix", true, // "Uniswap Compound", true, // "Uniswap CHAI", true, // "Uniswap Aave", false, // "Mooniswap", true, // "Uniswap V2", true, // "Uniswap V2 (ETH)", true, // "Uniswap V2 (DAI)", true, // "Uniswap V2 (USDC)", false, // "Curve Pax", false, // "Curve RenBTC", false, // "Curve tBTC", true, // "Dforce XSwap", false, // "Shell", true, // "mStable", false, // "Curve sBTC" true, // "Balancer 1" true, // "Balancer 2" true // "Balancer 3" ]; for (uint i = 0; i < DEXES_COUNT; i++) { if (args.distribution[i] > 0) { if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add(uint256( (value == VERY_NEGATIVE_VALUE ? 0 : value) + int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18)) )); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves(uint256 flags) internal pure returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory) { bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); return [ invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap, invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC, invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap, invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell, invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3 ]; } function _calculateNoGas( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*parts*/, uint256 /*destTokenEthPriceTimesGasPrice*/, uint256 /*flags*/, uint256 /*destTokenEthPrice*/ ) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) { this; } // View Helpers function _calculateBalancer( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/, uint256 poolIndex ) internal view returns(uint256[] memory rets, uint256 gas) { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (poolIndex >= pools.length) { return (new uint256[](parts), 0); } return ( balancerRegistry.getPoolReturns( pools[poolIndex], address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), _linearInterpolation(amount, parts) ), 500_000 ); } function calculateBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 0 ); } function calculateBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 1 ); } function calculateBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 2 ); } function calculateMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) || (destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd)) { return (rets, 0); } for (uint i = 1; i <= parts; i *= 2) { (bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector( musd.getSwapOutput.selector, fromToken, destToken, amount.mul(parts.div(i)).div(parts) )); if (success && data.length > 0) { (,, uint256 maxRet) = abi.decode(data, (bool,string,uint256)); if (maxRet > 0) { for (uint j = 0; j < parts.div(i); j++) { rets[j] = maxRet.mul(j + 1).div(parts.div(i)); } break; } } } return ( rets, 700_000 ); } function _calculateCurveSelector( ICurve curve, bytes4 sel, IERC20[] memory tokens, IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets) { int128 i = 0; int128 j = 0; for (uint t = 0; t < tokens.length; t++) { if (fromToken == tokens[t]) { i = int128(t + 1); } if (destToken == tokens[t]) { j = int128(t + 1); } } if (i == 0 || j == 0) { return new uint256[](parts); } // curve.get_dy(i - 1, j - 1, amount); // curve.get_dy_underlying(i - 1, j - 1, amount); (bool success, bytes memory data) = address(curve).staticcall(abi.encodeWithSelector(sel, i - 1, j - 1, amount)); uint256 maxRet = (!success || data.length == 0) ? 0 : abi.decode(data, (uint256)); return _linearInterpolation(maxRet, parts); } function calculateCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = dai; tokens[1] = usdc; return (_calculateCurveSelector( curveCompound, curveCompound.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 720_000); } function calculateCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; return (_calculateCurveSelector( curveUSDT, curveUSDT.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 720_000); } function calculateCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = tusd; return (_calculateCurveSelector( curveY, curveY.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 1_400_000); } function calculateCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = busd; return (_calculateCurveSelector( curveBinance, curveBinance.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 1_400_000); } function calculateCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = susd; return (_calculateCurveSelector( curveSynthetix, curveSynthetix.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 200_000); } function calculateCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = pax; return (_calculateCurveSelector( curvePAX, curvePAX.get_dy_underlying.selector, tokens, fromToken, destToken, amount, parts, flags ), 1_000_000); } function calculateCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = renbtc; tokens[1] = wbtc; return (_calculateCurveSelector( curveRenBTC, curveRenBTC.get_dy.selector, tokens, fromToken, destToken, amount, parts, flags ), 130_000); } function calculateCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = tbtc; tokens[1] = wbtc; tokens[2] = hbtc; return (_calculateCurveSelector( curveTBTC, curveTBTC.get_dy.selector, tokens, fromToken, destToken, amount, parts, flags ), 145_000); } function calculateCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = renbtc; tokens[1] = wbtc; tokens[2] = sbtc; return (_calculateCurveSelector( curveSBTC, curveSBTC.get_dy.selector, tokens, fromToken, destToken, amount, parts, flags ), 150_000); } function calculateShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector( shell.viewOriginTrade.selector, fromToken, destToken, amount )); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 300_000); } function calculateDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(dforceSwap).staticcall( abi.encodeWithSelector( dforceSwap.getAmountByInput.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); uint256 available = destToken.universalBalanceOf(address(dforceSwap)); if (maxRet > available) { return (new uint256[](parts), 0); } return (_linearInterpolation(maxRet, parts), 160_000); } function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) { return amount.mul(toBalance).mul(997).div( fromBalance.mul(1000).add(amount.mul(997)) ); } function _calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = amounts; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange)); uint256 fromEtherBalance = address(fromExchange).balance; for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 toEtherBalance = address(toExchange).balance; uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange)); for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]); } } return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000); } function calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswap( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function _calculateUniswapWrapped( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 midTokenPrice, uint256 flags, uint256 gas1, uint256 gas2 ) internal view returns(uint256[] memory rets, uint256 gas) { if (!fromToken.isETH() && destToken.isETH()) { (rets, gas) = _calculateUniswap( midToken, destToken, _linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts), flags ); return (rets, gas + gas1); } else if (fromToken.isETH() && !destToken.isETH()) { (rets, gas) = _calculateUniswap( fromToken, midToken, _linearInterpolation(amount, parts), flags ); for (uint i = 0; i < parts; i++) { rets[i] = rets[i].mul(midTokenPrice).div(1e18); } return (rets, gas + gas2); } return (new uint256[](parts), 0); } function calculateUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { ICompoundToken midToken = _getCompoundToken(midPreToken); if (midToken != ICompoundToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, midToken.exchangeRateStored(), flags, 200_000, 200_000 ); } } return (new uint256[](parts), 0); } function calculateUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai && destToken.isETH() || fromToken.isETH() && destToken == dai) { return _calculateUniswapWrapped( fromToken, chai, destToken, amount, parts, chai.chaiPrice(), flags, 180_000, 160_000 ); } return (new uint256[](parts), 0); } function calculateUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { IAaveToken midToken = _getAaveToken(midPreToken); if (midToken != IAaveToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, 1e18, flags, 310_000, 670_000 ); } } return (new uint256[](parts), 0); } function _calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal view returns(uint256 returnAmount, uint256 gas) { (bool success, bytes memory data) = address(kyberNetworkProxy).staticcall.gas(2300)(abi.encodeWithSelector( kyberNetworkProxy.kyberNetworkContract.selector )); if (!success || data.length == 0) { return (0, 0); } IKyberNetworkContract kyberNetworkContract = IKyberNetworkContract(abi.decode(data, (address))); if (fromToken.isETH() || destToken.isETH()) { return _calculateKyberWithEth(kyberNetworkContract, fromToken, destToken, amount, flags); } (uint256 value, uint256 gasFee) = _calculateKyberWithEth(kyberNetworkContract, fromToken, ETH_ADDRESS, amount, flags); if (value == 0) { return (0, 0); } (uint256 value2, uint256 gasFee2) = _calculateKyberWithEth(kyberNetworkContract, ETH_ADDRESS, destToken, value, flags); return (value2, gasFee + gasFee2); } function _calculateKyberWithEth( IKyberNetworkContract kyberNetworkContract, IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal view returns(uint256 returnAmount, uint256 gas) { require(fromToken.isETH() || destToken.isETH(), "2ETH"); (bool success, bytes memory data) = address(kyberNetworkContract).staticcall.gas(1500000)(abi.encodeWithSelector( kyberNetworkContract.searchBestRate.selector, fromToken.isETH() ? ETH_ADDRESS : fromToken, destToken.isETH() ? ETH_ADDRESS : destToken, amount, true )); if (!success) { return (0, 0); } (address reserve, uint256 ret) = abi.decode(data, (address,uint256)); if (ret == 0) { return (0, 0); } if ((reserve == 0x31E085Afd48a1d6e51Cc193153d625e8f0514C7F && !flags.check(FLAG_ENABLE_KYBER_UNISWAP_RESERVE)) || (reserve == 0x1E158c0e93c30d24e918Ef83d1e0bE23595C3c0f && !flags.check(FLAG_ENABLE_KYBER_OASIS_RESERVE)) || (reserve == 0x053AA84FCC676113a57e0EbB0bD1913839874bE4 && !flags.check(FLAG_ENABLE_KYBER_BANCOR_RESERVE))) { return (0, 0); } if (!flags.check(FLAG_ENABLE_KYBER_UNISWAP_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberUniswapReserve(reserve).uniswapFactory.selector )); if (success) { return (0, 0); } } if (!flags.check(FLAG_ENABLE_KYBER_OASIS_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberOasisReserve(reserve).otc.selector )); if (success) { return (0, 0); } } if (!flags.check(FLAG_ENABLE_KYBER_BANCOR_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberBancorReserve(reserve).bancorEth.selector )); if (success) { return (0, 0); } } return ( ret.mul(amount) .mul(10 ** IERC20(destToken).universalDecimals()) .div(10 ** IERC20(fromToken).universalDecimals()) .div(1e18), 700_000 ); } function calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { (rets[i], gas) = _calculateKyber(fromToken, destToken, amount.mul(i + 1).div(parts), flags); if (rets[i] == 0) { break; } } return (rets, gas); } function calculateBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = _buildBancorPath(fromToken, destToken); rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)( abi.encodeWithSelector( bancorNetwork.getReturnByPath.selector, path, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { (uint256 ret,) = abi.decode(data, (uint256,uint256)); rets[i] = ret; } } return (rets, path.length.mul(150_000)); } function calculateOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)( abi.encodeWithSelector( oasisExchange.getBuyAmount.selector, destToken.isETH() ? weth : destToken, fromToken.isETH() ? weth : fromToken, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { rets[i] = abi.decode(data, (uint256)); } } return (rets, 500_000); } function calculateMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IMooniswap mooniswap = mooniswapRegistry.target(); (bool success, bytes memory data) = address(mooniswap).staticcall.gas(1000000)( abi.encodeWithSelector( mooniswap.getReturn.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 1_000_000); } function calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswapV2( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function calculateUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, weth, destToken, amount, parts, flags ); } function calculateUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai || destToken == dai) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, dai, destToken, amount, parts, flags ); } function calculateUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == usdc || destToken == usdc) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, usdc, destToken, amount, parts, flags ); } function _calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 destTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal); if (exchange != IUniswapV2Exchange(0)) { uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange)); uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange)); for (uint i = 0; i < amounts.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]); } return (rets, 50_000); } } function _calculateUniswapV2OverMidToken( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); uint256 gas1; uint256 gas2; (rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags); (rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags); return (rets, gas1 + gas2); } function _calculateNoReturn( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { this; return (new uint256[](parts), 0); } } contract OneSplitBaseWrap is IOneSplit, OneSplitRoot { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) internal { if (fromToken == destToken) { return; } _swapFloor( fromToken, destToken, amount, distribution, flags ); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) internal; } contract OneSplit is IOneSplit, OneSplitRoot { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplitView) public { oneSplitView = _oneSplitView; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) public payable returns(uint256 returnAmount) { if (fromToken == destToken) { return amount; } function(IERC20,IERC20,uint256) returns(uint256)[DEXES_COUNT] memory reserves = [ _swapOnUniswap, _swapOnKyber, _swapOnBancor, _swapOnOasis, _swapOnCurveCompound, _swapOnCurveUSDT, _swapOnCurveY, _swapOnCurveBinance, _swapOnCurveSynthetix, _swapOnUniswapCompound, _swapOnUniswapChai, _swapOnUniswapAave, _swapOnMooniswap, _swapOnUniswapV2, _swapOnUniswapV2ETH, _swapOnUniswapV2DAI, _swapOnUniswapV2USDC, _swapOnCurvePAX, _swapOnCurveRenBTC, _swapOnCurveTBTC, _swapOnDforceSwap, _swapOnShell, _swapOnMStableMUSD, _swapOnCurveSBTC, _swapOnBalancer1, _swapOnBalancer2, _swapOnBalancer3 ]; require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size"); uint256 parts = 0; uint256 lastNonZeroIndex = 0; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { parts = parts.add(distribution[i]); lastNonZeroIndex = i; } } if (parts == 0) { if (fromToken.isETH()) { msg.sender.transfer(msg.value); return msg.value; } return amount; } fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); for (uint i = 0; i < distribution.length; i++) { if (distribution[i] == 0) { continue; } uint256 swapAmount = amount.mul(distribution[i]).div(parts); if (i == lastNonZeroIndex) { swapAmount = remainingAmount; } remainingAmount -= swapAmount; reserves[i](fromToken, destToken, swapAmount); } returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: Return amount was not enough"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } // Swap helpers function _swapOnCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveCompound), amount); curveCompound.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveUSDT), amount); curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == tusd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == tusd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveY), amount); curveY.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == busd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == busd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveBinance), amount); curveBinance.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == susd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == susd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveSynthetix), amount); curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == pax ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == pax ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curvePAX), amount); curvePAX.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnShell( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns (uint256) { fromToken.universalApprove(address(shell), amount); return shell.swapByOrigin( address(fromToken), address(destToken), amount, 0, now + 50 ); } function _swapOnMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns (uint256) { fromToken.universalApprove(address(musd), amount); return musd.swap( fromToken, destToken, amount, address(this) ); } function _swapOnCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveRenBTC), amount); curveRenBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == tbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == hbtc ? 3 : 0); int128 j = (destToken == tbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == hbtc ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveTBTC), amount); curveTBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == sbtc ? 3 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == sbtc ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveSBTC), amount); curveSBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { fromToken.universalApprove(address(dforceSwap), amount); dforceSwap.swap(fromToken, destToken, amount); } function _swapOnUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { fromToken.universalApprove(address(fromExchange), returnAmount); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } return returnAmount; } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { ICompoundToken fromCompound = _getCompoundToken(fromToken); fromToken.universalApprove(address(fromCompound), amount); fromCompound.mint(amount); return _swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this))); } if (!destToken.isETH()) { ICompoundToken toCompound = _getCompoundToken(destToken); uint256 compoundAmount = _swapOnUniswap(fromToken, IERC20(toCompound), amount); toCompound.redeem(compoundAmount); return destToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (fromToken == dai) { fromToken.universalApprove(address(chai), amount); chai.join(address(this), amount); return _swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this))); } if (destToken == dai) { uint256 chaiAmount = _swapOnUniswap(fromToken, IERC20(chai), amount); chai.exit(address(this), chaiAmount); return destToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { IAaveToken fromAave = _getAaveToken(fromToken); fromToken.universalApprove(aave.core(), amount); aave.deposit(fromToken, amount, 1101); return _swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this))); } if (!destToken.isETH()) { IAaveToken toAave = _getAaveToken(destToken); uint256 aaveAmount = _swapOnUniswap(fromToken, IERC20(toAave), amount); toAave.redeem(aaveAmount); return aaveAmount; } return 0; } function _swapOnMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { IMooniswap mooniswap = mooniswapRegistry.target(); fromToken.universalApprove(address(mooniswap), amount); return mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0 ); } function _swapOnKyber( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { fromToken.universalApprove(address(kyberNetworkProxy), amount); return kyberNetworkProxy.tradeWithHint.value(fromToken.isETH() ? amount : 0)( fromToken.isETH() ? ETH_ADDRESS : fromToken, amount, destToken.isETH() ? ETH_ADDRESS : destToken, address(this), 1 << 255, 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, "" ); } function _swapOnBancor( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = _buildBancorPath(fromToken, destToken); fromToken.universalApprove(address(bancorNetwork), amount); return bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1); } function _swapOnOasis( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 approveToken = fromToken.isETH() ? weth : fromToken; approveToken.universalApprove(address(oasisExchange), amount); uint256 returnAmount = oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 1 ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } return returnAmount; } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal); returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount); fromTokenReal.universalTransfer(address(exchange), amount); if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) { exchange.swap(0, returnAmount, address(this), ""); } else { exchange.swap(returnAmount, 0, address(this), ""); } if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( midToken, destToken, _swapOnUniswapV2Internal( fromToken, midToken, amount ) ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( fromToken, destToken, amount ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, weth, destToken, amount ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, dai, destToken, amount ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, usdc, destToken, amount ); } function _swapOnBalancerX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 poolIndex ) internal returns(uint256) { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (fromToken.isETH()) { weth.deposit.value(amount)(); } (fromToken.isETH() ? weth : destToken).universalApprove(pools[poolIndex], amount); IBalancerPool(pools[poolIndex]).swapExactAmountIn( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 0, uint256(-1) ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 0); } function _swapOnBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 1); } function _swapOnBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 2); } } // File: contracts/OneSplitMultiPath.sol pragma solidity ^0.5.0; contract OneSplitMultiPathBase is IOneSplitConsts, OneSplitRoot { function _getMultiPathToken(uint256 flags) internal pure returns(IERC20 midToken) { uint256[7] memory allFlags = [ FLAG_ENABLE_MULTI_PATH_ETH, FLAG_ENABLE_MULTI_PATH_DAI, FLAG_ENABLE_MULTI_PATH_USDC, FLAG_ENABLE_MULTI_PATH_USDT, FLAG_ENABLE_MULTI_PATH_WBTC, FLAG_ENABLE_MULTI_PATH_TBTC, FLAG_ENABLE_MULTI_PATH_RENBTC ]; IERC20[7] memory allMidTokens = [ ETH_ADDRESS, dai, usdc, usdt, wbtc, tbtc, renbtc ]; for (uint i = 0; i < allFlags.length; i++) { if (flags.check(allFlags[i])) { require(midToken == IERC20(0), "OneSplit: Do not use multipath with each other"); midToken = allMidTokens[i]; } } } function _getFlagsByDistribution(uint256[] memory distribution) internal pure returns(uint256 flags) { uint256[DEXES_COUNT] memory sourcesFlags = [ FLAG_DISABLE_UNISWAP, FLAG_DISABLE_KYBER, FLAG_DISABLE_BANCOR, FLAG_DISABLE_OASIS, FLAG_DISABLE_CURVE_COMPOUND, FLAG_DISABLE_CURVE_USDT, FLAG_DISABLE_CURVE_Y, FLAG_DISABLE_CURVE_BINANCE, FLAG_DISABLE_CURVE_SYNTHETIX, FLAG_DISABLE_UNISWAP_COMPOUND, FLAG_DISABLE_UNISWAP_CHAI, FLAG_DISABLE_UNISWAP_AAVE, FLAG_DISABLE_MOONISWAP, FLAG_DISABLE_UNISWAP_V2, FLAG_DISABLE_UNISWAP_V2_ETH, FLAG_DISABLE_UNISWAP_V2_DAI, FLAG_DISABLE_UNISWAP_V2_USDC, FLAG_DISABLE_CURVE_PAX, FLAG_DISABLE_CURVE_RENBTC, FLAG_DISABLE_CURVE_TBTC, FLAG_DISABLE_DFORCE_SWAP, FLAG_DISABLE_SHELL, FLAG_DISABLE_MSTABLE_MUSD, FLAG_DISABLE_CURVE_SBTC, 0, 0, 0 ]; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { flags |= sourcesFlags[i]; } } } } contract OneSplitMultiPathView is OneSplitViewWrapBase, OneSplitMultiPathBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns ( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } IERC20 midToken = _getMultiPathToken(flags); if (midToken != IERC20(0)) { if (_tokensEqual(fromToken, midToken) || _tokensEqual(midToken, destToken)) { return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } // Stack too deep uint256 _flags = flags; IERC20 _destToken = destToken; uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, midToken, amount, parts, _flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, midToken, _destTokenEthPriceTimesGasPrice ) ); uint256[] memory dist; uint256 estimateGasAmount2; (returnAmount, estimateGasAmount2, dist) = super.getExpectedReturnWithGas( midToken, destToken, returnAmount, parts, _flags | _getFlagsByDistribution(distribution), destTokenEthPriceTimesGasPrice ); for (uint i = 0; i < distribution.length; i++) { distribution[i] = distribution[i].add(dist[i] << 8); } return (returnAmount, estimateGasAmount + estimateGasAmount2, distribution); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMultiPath is OneSplitBaseWrap, OneSplitMultiPathBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { IERC20 midToken = _getMultiPathToken(flags); if (midToken != IERC20(0) && !_tokensEqual(fromToken, midToken) && !_tokensEqual(midToken, destToken)) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & 0xFF; } super._swap( fromToken, midToken, amount, dist, flags ); uint256 additionalFlags = _getFlagsByDistribution(distribution); for (uint i = 0; i < distribution.length; i++) { dist[i] = (distribution[i] >> 8) & 0xFF; } super._swap( midToken, destToken, midToken.universalBalanceOf(address(this)), dist, flags | additionalFlags ); return; } super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitCompound.sol pragma solidity ^0.5.0; contract OneSplitCompoundBase { function _getCompoundUnderlyingToken(IERC20 token) internal pure returns(IERC20) { if (token == IERC20(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5)) { // ETH return IERC20(0); } if (token == IERC20(0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643)) { // DAI return IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); } if (token == IERC20(0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E)) { // BAT return IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF); } if (token == IERC20(0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1)) { // REP return IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862); } if (token == IERC20(0x39AA39c021dfbaE8faC545936693aC917d5E7563)) { // USDC return IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); } if (token == IERC20(0xC11b1268C1A384e55C48c2391d8d480264A3A7F4)) { // WBTC return IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); } if (token == IERC20(0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407)) { // ZRX return IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498); } if (token == IERC20(0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9)) { // USDT return IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); } return IERC20(-1); } } contract OneSplitCompoundView is OneSplitViewWrapBase, OneSplitCompoundBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = _getCompoundUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn( underlying, destToken, amount.mul(compoundRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getCompoundUnderlyingToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18) ); return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitCompound is OneSplitBaseWrap, OneSplitCompoundBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compoundSwap( fromToken, destToken, amount, distribution, flags ); } function _compoundSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = _getCompoundUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { ICompoundToken(address(fromToken)).redeem(amount); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return _compoundSwap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _getCompoundUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { cETH.mint.value(underlyingAmount)(); } else { underlying.universalApprove(address(destToken), underlyingAmount); ICompoundToken(address(destToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IFulcrum.sol pragma solidity ^0.5.0; contract IFulcrumToken is IERC20 { function tokenPrice() external view returns (uint256); function loanTokenAddress() external view returns (address); function mintWithEther(address receiver) external payable returns (uint256 mintAmount); function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount); function burnToEther(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); } // File: contracts/OneSplitFulcrum.sol pragma solidity ^0.5.0; contract OneSplitFulcrumBase { using UniversalERC20 for IERC20; function _isFulcrumToken(IERC20 token) internal view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature( "name()" )); if (!success) { return IERC20(-1); } bool foundBZX = false; for (uint i = 0; i + 6 < data.length; i++) { if (data[i + 0] == "F" && data[i + 1] == "u" && data[i + 2] == "l" && data[i + 3] == "c" && data[i + 4] == "r" && data[i + 5] == "u" && data[i + 6] == "m") { foundBZX = true; break; } } if (!foundBZX) { return IERC20(-1); } (success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( IFulcrumToken(address(token)).loanTokenAddress.selector )); if (!success) { return IERC20(-1); } return abi.decode(data, (IERC20)); } } contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn( underlying, destToken, amount.mul(fulcrumRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 381_000, distribution); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18) ); return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, destToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { if (underlying.isETH()) { IFulcrumToken(address(fromToken)).burnToEther(address(this), amount); } else { IFulcrumToken(address(fromToken)).burn(address(this), amount); } uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return super._swap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { underlying.universalApprove(address(destToken), underlyingAmount); IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, chai.chaiToDai(amount), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 197_000, distribution); } if (destToken == IERC20(chai)) { uint256 price = chai.chaiPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(1e18).div(price) ); return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } if (destToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(chai), daiBalance); chai.join(address(this), daiBalance); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IBdai.sol pragma solidity ^0.5.0; contract IBdai is IERC20 { function join(uint256) external; function exit(uint256) external; } // File: contracts/OneSplitBdai.sol pragma solidity ^0.5.0; contract OneSplitBdaiBase { IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 227_000, distribution); } if (destToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { bdai.exit(amount); uint256 btuBalance = btu.balanceOf(address(this)); if (btuBalance > 0) { (,uint256[] memory btuDistribution) = getExpectedReturn( btu, destToken, btuBalance, 1, flags ); _swap( btu, destToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, destToken, amount, distribution, flags ); } if (destToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(bdai), daiBalance); bdai.join(daiBalance); return; } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIearn.sol pragma solidity ^0.5.0; contract IIearn is IERC20 { function token() external view returns(IERC20); function calcPoolValueInToken() external view returns(uint256); function deposit(uint256 _amount) external; function withdraw(uint256 _shares) external; } // File: contracts/OneSplitIearn.sol pragma solidity ^0.5.0; contract OneSplitIearnBase { function _yTokens() internal pure returns(IIearn[13] memory) { return [ IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01), IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9), IIearn(0x73a052500105205d34Daf004eAb301916DA8190f), IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D), IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e), IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600), IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE), IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32), IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447), IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951), IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc), IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E), IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59) ]; } } contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _iearnGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { (returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn( yTokens[i].token(), destToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 260_000, distribution); } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; IERC20 token = yTokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()) ); return( returnAmount .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), estimateGasAmount + 743_000, distribution ); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, destToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(yTokens[i]), underlyingBalance); yTokens[i].deposit(underlyingBalance); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIdle.sol pragma solidity ^0.5.0; contract IIdle is IERC20 { function token() external view returns (IERC20); function tokenPrice() external view returns (uint256); function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts) external returns (uint256 mintedTokens); function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts) external returns (uint256 redeemedTokens); } // File: contracts/OneSplitIdle.sol pragma solidity ^0.5.0; contract OneSplitIdleBase { function _idleTokens() internal pure returns(IIdle[8] memory) { // https://developers.idle.finance/contracts-and-codebase return [ // V3 IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934), IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6), IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D), IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB), IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C), IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B), // V2 IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _idleGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { (returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn( tokens[i].token(), destToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 2_400_000, distribution); } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 _price = tokens[i].tokenPrice(); IERC20 token = tokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(_price).div(1e18) ); return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, destToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0)); _idleSwap(underlying, destToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(tokens[i]), underlyingBalance); tokens[i].mintIdleToken(underlyingBalance, new uint256[](0)); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/OneSplitAave.sol pragma solidity ^0.5.0; contract OneSplitAaveBase { function _getAaveUnderlyingToken(IERC20 token) internal pure returns(IERC20) { if (token == IERC20(0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04)) { // ETH return IERC20(0); } if (token == IERC20(0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d)) { // DAI return IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); } if (token == IERC20(0x9bA00D6856a4eDF4665BcA2C2309936572473B7E)) { // USDC return IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); } if (token == IERC20(0x625aE63000f46200499120B906716420bd059240)) { // SUSD return IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); } if (token == IERC20(0x6Ee0f7BB50a54AB5253dA0667B0Dc2ee526C30a8)) { // BUSD return IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); } if (token == IERC20(0x4DA9b813057D04BAef4e5800E36083717b4a0341)) { // TUSD return IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); } if (token == IERC20(0x71fc860F7D3A592A4a98740e39dB31d25db65ae8)) { // USDT return IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); } if (token == IERC20(0xE1BA0FB44CCb0D11b80F92f4f8Ed94CA3fF51D00)) { // BAT return IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF); } if (token == IERC20(0x9D91BE44C06d373a8a226E1f3b146956083803eB)) { // KNC return IERC20(0xdd974D5C2e2928deA5F71b9825b8b646686BD200); } if (token == IERC20(0x7D2D3688Df45Ce7C552E19c27e007673da9204B8)) { // LEND return IERC20(0x80fB784B7eD66730e8b1DBd9820aFD29931aab03); } if (token == IERC20(0xA64BD6C70Cb9051F6A9ba1F163Fdc07E0DfB5F84)) { // LINK return IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA); } if (token == IERC20(0x6FCE4A401B6B80ACe52baAefE4421Bd188e76F6f)) { // MANA return IERC20(0x0F5D2fB29fb7d3CFeE444a200298f468908cC942); } if (token == IERC20(0x7deB5e830be29F91E298ba5FF1356BB7f8146998)) { // MKR return IERC20(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2); } if (token == IERC20(0x71010A9D003445aC60C4e6A7017c1E89A477B438)) { // REP return IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862); } if (token == IERC20(0x328C4c80BC7aCa0834Db37e6600A6c49E12Da4DE)) { // SNX return IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F); } if (token == IERC20(0xFC4B8ED459e00e5400be803A9BB3954234FD50e3)) { // WBTC return IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); } if (token == IERC20(0x6Fb0855c404E09c47C3fBCA25f08d4E41f9F062f)) { // ZRX return IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498); } return IERC20(-1); } } contract OneSplitAaveView is OneSplitViewWrapBase, OneSplitAaveBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { (returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn( underlying, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 670_000, distribution); } underlying = _getAaveUnderlyingToken(destToken); if (underlying != IERC20(-1)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 310_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitAave is OneSplitBaseWrap, OneSplitAaveBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, destToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, destToken, amount, distribution, flags ); } underlying = _getAaveUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); underlying.universalApprove(aave.core(), underlyingAmount); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice); } if (destToken == weth || destToken == bancorEtherToken) { return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, destToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (destToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (destToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitMStable.sol pragma solidity ^0.5.0; contract OneSplitMStableView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, destToken); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, dai); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, returnAmount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 300_000, distribution); } } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { (,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { IERC20 _destToken = destToken; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, dai, destTokenEthPriceTimesGasPrice ) ); (,, returnAmount) = musd_helper.getRedeemValidity(dai, returnAmount, destToken); return (returnAmount, estimateGasAmount + 300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMStable is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken); musd.redeem( destToken, result ); } else { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai); musd.redeem( dai, result ); super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } return; } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } else { super._swap( fromToken, dai, amount, distribution, flags ); musd.swap( dai, destToken, dai.balanceOf(address(this)), address(this) ); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IDMM.sol pragma solidity ^0.5.0; interface IDMMController { function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20); } contract IDMM is IERC20 { function getCurrentExchangeRate() public view returns(uint256); function mint(uint256 underlyingAmount) public returns(uint256); function redeem(uint256 amount) public returns(uint256); } // File: contracts/OneSplitDMM.sol pragma solidity ^0.5.0; contract OneSplitDMMBase { IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2); function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) { (bool success, bytes memory data) = address(_dmmController).staticcall( abi.encodeWithSelector( _dmmController.getUnderlyingTokenForDmm.selector, token ) ); if (!success || data.length == 0) { return IERC20(-1); } return abi.decode(data, (IERC20)); } function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) { (bool success, bytes memory data) = address(dmm).staticcall( abi.encodeWithSelector( dmm.getCurrentExchangeRate.selector ) ); if (!success || data.length == 0) { return 0; } return abi.decode(data, (uint256)); } } contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _dmmGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _dmmGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } IERC20 _fromToken = fromToken; (returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn( underlying, destToken, amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } uint256 price = _getDMMExchangeRate(IDMM(address(destToken))); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(price).div(1e18) ); return ( returnAmount.mul(1e18).div(price), estimateGasAmount + 430_000, distribution ); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _dmmSwap( fromToken, destToken, amount, distribution, flags ); } function _dmmSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IDMM(address(fromToken)).redeem(amount); uint256 balance = underlying.universalBalanceOf(address(this)); if (underlying == weth) { weth.withdraw(balance); } _dmmSwap( (underlying == weth) ? ETH_ADDRESS : underlying, destToken, balance, distribution, flags ); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, (underlying == weth) ? ETH_ADDRESS : underlying, amount, distribution, flags ); uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this)); if (underlying == weth) { weth.deposit.value(underlyingAmount); } underlying.universalApprove(address(destToken), underlyingAmount); IDMM(address(destToken)).mint(underlyingAmount); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; //import "./OneSplitSmartToken.sol"; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMStableView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, OneSplitDMMView, OneSplitMultiPathView //OneSplitSmartTokenView { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplit) public { oneSplitView = _oneSplit; } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWrap is OneSplitBaseWrap, OneSplitMStable, OneSplitChai, OneSplitBdai, OneSplitAave, OneSplitFulcrum, OneSplitCompound, OneSplitIearn, OneSplitIdle, OneSplitWeth, OneSplitDMM, OneSplitMultiPath //OneSplitSmartToken { IOneSplitView public oneSplitView; IOneSplit public oneSplit; constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public { oneSplitView = _oneSplitView; oneSplit = _oneSplit; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount) { fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 confirmed = fromToken.universalBalanceOf(address(this)); _swap(fromToken, destToken, confirmed, distribution, flags); returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { fromToken.universalApprove(address(oneSplit), amount); oneSplit.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0, distribution, flags ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IOneSplitView","name":"_oneSplitView","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"getExpectedReturn","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"destTokenEthPriceTimesGasPrice","type":"uint256"}],"name":"getExpectedReturnWithGas","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplitView","outputs":[{"internalType":"contract IOneSplitView","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405162004e6a38038062004e6a8339818101604052602081101561003557600080fd5b5051600080546001600160a01b039092166001600160a01b0319909216919091179055614e0280620000686000396000f3fe60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed951461028b575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102bc565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102df565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610279600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a08101608082013564010000000081111561020557600080fd5b82018360208201111561021757600080fd5b8035906020019184602083028401116401000000008311171561023957600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610438915050565b60408051918252519081900360200190f35b34801561029757600080fd5b506102a06107d9565b604080516001600160a01b039092168252519081900360200190f35b600060606102cf878787878760006102df565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035257600080fd5b505afa158015610366573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038f57600080fd5b815160208301516040808501805191519395929483019291846401000000008211156103ba57600080fd5b9083019060208201858111156103cf57600080fd5b82518660208202830111640100000000821117156103ec57600080fd5b82525081516020918201928201910280838360005b83811015610419578181015183820152602001610401565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b0316141561045b5750836107cf565b610463614c2e565b6040518061036001604052806107e88152602001610a798152602001610c148152602001610dbf8152602001611090815260200161122b815260200161140c815260200161164181526020016118808152602001611abf8152602001611c6d8152602001611e29815260200161201e81526020016121768152602001612183815260200161219f81526020016121bb81526020016121d7815260200161241681526020016125a881526020016127a1815260200161285a815260200161293381526020016129d48152602001612bcd8152602001612be48152602001612bf38152509050601b845111156105885760405162461bcd60e51b8152600401808060200182810382526042815260200180614d8c6042913960600191505060405180910390fd5b600080805b86518110156105e65760008782815181106105a457fe5b602002602001015111156105de576105d88782815181106105c157fe5b602002602001015184612c0290919063ffffffff16565b92508091505b60010161058d565b5081610646576105fe8a6001600160a01b0316612c65565b1561063b5760405133903480156108fc02916000818181858888f1935050505015801561062f573d6000803e3d6000fd5b503493505050506107cf565b8793505050506107cf565b6106616001600160a01b038b1633308b63ffffffff612ca116565b600061067c6001600160a01b038c163063ffffffff612dc016565b905060005b875181101561071f5787818151811061069657fe5b6020026020010151600014156106ab57610717565b60006106e3856106d78b85815181106106c057fe5b60200260200101518e612e6a90919063ffffffff16565b9063ffffffff612ec316565b9050838214156106f05750815b80830392506107148d8d838986601b811061070757fe5b602002015163ffffffff16565b50505b600101610681565b506107396001600160a01b038b163063ffffffff612dc016565b94508785101561077a5760405162461bcd60e51b8152600401808060200182810382526026815260200180614d066026913960400191505060405180910390fd5b6107946001600160a01b038b16338763ffffffff612f0516565b506107c9336107b26001600160a01b038e163063ffffffff612dc016565b6001600160a01b038e16919063ffffffff612f0516565b50505050505b9695505050505050565b6000546001600160a01b031681565b6000816107fd6001600160a01b038616612c65565b61093d57604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561085f57600080fd5b505afa158015610873573d6000803e3d6000fd5b505050506040513d602081101561088957600080fd5b505190506001600160a01b0381161561093b576108b66001600160a01b038716828463ffffffff612f8016565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561090c57600080fd5b505af1158015610920573d6000803e3d6000fd5b505050506040513d602081101561093657600080fd5b505191505b505b61094f846001600160a01b0316612c65565b610a6f57604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109b157600080fd5b505afa1580156109c5573d6000803e3d6000fd5b505050506040513d60208110156109db57600080fd5b505190506001600160a01b03811615610a6d57806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a3d57600080fd5b505af1158015610a51573d6000803e3d6000fd5b50505050506040513d6020811015610a6857600080fd5b505191505b505b90505b9392505050565b6000610aa96001600160a01b03851673818e6fecd516ecc3849daf6845e3ec868087b7558463ffffffff612f8016565b73818e6fecd516ecc3849daf6845e3ec868087b7556329589f61610ad56001600160a01b038716612c65565b610ae0576000610ae2565b835b610af4876001600160a01b0316612c65565b610afe5786610b14565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b85610b27886001600160a01b0316612c65565b610b315787610b47565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e088901b1681526001600160a01b039485166004820152602481019390935292166044820152306064820152600160ff1b6084820152600060a48201819052734d37f28d2db99e8d35a6c725a5f1749a085850a360c483015261010060e4830152610104820152905161014480830192602092919082900301818588803b158015610bdf57600080fd5b505af1158015610bf3573d6000803e3d6000fd5b50505050506040513d6020811015610c0a57600080fd5b5051949350505050565b6000807352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610c7f57600080fd5b505afa158015610c93573d6000803e3d6000fd5b505050506040513d6020811015610ca957600080fd5b505190506060610cb98686613079565b9050610cd56001600160a01b038716838663ffffffff612f8016565b816001600160a01b031663f3898a97610cf6886001600160a01b0316612c65565b610d01576000610d03565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610d62578181015183820152602001610d4a565b505050509050019450505050506020604051808303818588803b158015610d8857600080fd5b505af1158015610d9c573d6000803e3d6000fd5b50505050506040513d6020811015610db357600080fd5b50519695505050505050565b6000610dd3846001600160a01b0316612c65565b15610e3b57600080516020614c5a8339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50505050505b6000610e4f856001600160a01b0316612c65565b610e595784610e69565b600080516020614c5a8339815191525b9050610e996001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff612f8016565b600073794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610ec76001600160a01b038916612c65565b610ed15787610ee1565b600080516020614c5a8339815191525b86610ef4896001600160a01b0316612c65565b610efe5788610f0e565b600080516020614c5a8339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610f6c57600080fd5b505af1158015610f80573d6000803e3d6000fd5b505050506040513d6020811015610f9657600080fd5b50519050610fac6001600160a01b038616612c65565b1561108757604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561100457600080fd5b505afa158015611018573d6000803e3d6000fd5b505050506040513d602081101561102e57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561106e57600080fd5b505af1158015611082573d6000803e3d6000fd5b505050505b95945050505050565b6000806001600160a01b038516600080516020614ce6833981519152146110b85760006110bb565b60025b6001600160a01b038616600080516020614c7a833981519152146110e05760006110e3565b60015b0160ff1690506000600080516020614ce68339815191526001600160a01b03861614611110576000611113565b60025b6001600160a01b038616600080516020614c7a8339815191521461113857600061113b565b60015b0160ff16905081600f0b60001480611156575080600f0b6000145b1561116657600092505050610a72565b6111946001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b505af115801561121e573d6000803e3d6000fd5b5050505050509392505050565b6000806001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec71461125957600061125c565b60035b6001600160a01b038616600080516020614ce683398151915214611281576000611284565b60025b6001600160a01b038716600080516020614c7a833981519152146112a95760006112ac565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b0316146112e95760006112ec565b60035b6001600160a01b038616600080516020614ce683398151915214611311576000611314565b60025b6001600160a01b038716600080516020614c7a8339815191521461133957600061133c565b60015b010160ff16905081600f0b60001480611358575080600f0b6000145b1561136857600092505050610a72565b6113966001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b0385166e085d4780b73119b644ae5ecd22b37614611435576000611438565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611463576000611466565b60035b6001600160a01b038716600080516020614ce68339815191521461148b57600061148e565b60025b6001600160a01b038816600080516020614c7a833981519152146114b35760006114b6565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b0316146114ef5760006114f2565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461151d576000611520565b60035b6001600160a01b038716600080516020614ce683398151915214611545576000611548565b60025b6001600160a01b038816600080516020614c7a8339815191521461156d576000611570565b60015b01010160ff16905081600f0b6000148061158d575080600f0b6000145b1561159d57600092505050610a72565b6115cb6001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c531461166f576000611672565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461169d5760006116a0565b60035b6001600160a01b038716600080516020614ce6833981519152146116c55760006116c8565b60025b6001600160a01b038816600080516020614c7a833981519152146116ed5760006116f0565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b03161461172e576000611731565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461175c57600061175f565b60035b6001600160a01b038716600080516020614ce683398151915214611784576000611787565b60025b6001600160a01b038816600080516020614c7a833981519152146117ac5760006117af565b60015b01010160ff16905081600f0b600014806117cc575080600f0b6000145b156117dc57600092505050610a72565b61180a6001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f51146118ae5760006118b1565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146118dc5760006118df565b60035b6001600160a01b038716600080516020614ce683398151915214611904576000611907565b60025b6001600160a01b038816600080516020614c7a8339815191521461192c57600061192f565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b03161461196d576000611970565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461199b57600061199e565b60035b6001600160a01b038716600080516020614ce6833981519152146119c35760006119c6565b60025b6001600160a01b038816600080516020614c7a833981519152146119eb5760006119ee565b60015b01010160ff16905081600f0b60001480611a0b575080600f0b6000145b15611a1b57600092505050610a72565b611a496001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000611ad3846001600160a01b0316612c65565b611b9c576000611ae285613814565b9050611afe6001600160a01b038616828563ffffffff612f8016565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611b4457600080fd5b505af1158015611b58573d6000803e3d6000fd5b505050506040513d6020811015611b6e57600080fd5b50611b9490508185611b8f6001600160a01b0383163063ffffffff612dc016565b6107e8565b915050610a72565b611bae836001600160a01b0316612c65565b611c63576000611bbd84613814565b90506000611bcc8683866107e8565b9050816001600160a01b031663db006a75826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c1457600080fd5b505af1158015611c28573d6000803e3d6000fd5b505050506040513d6020811015611c3e57600080fd5b50611c5a90506001600160a01b0386163063ffffffff612dc016565b92505050610a72565b5060009392505050565b60006001600160a01b038416600080516020614c7a8339815191521415611d6057611cbc6001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff612f8016565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611d1557600080fd5b505af1158015611d29573d6000803e3d6000fd5b50611d5992507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611b8f823063ffffffff612dc016565b9050610a72565b6001600160a01b038316600080516020614c7a8339815191521415611c63576000611da0857306af07097c9eeb7fd685c692751d5c66db49c215856107e8565b6040805163ef693bed60e01b81523060048201526024810183905290519192507306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed9160448082019260009290919082900301818387803b158015611dfd57600080fd5b505af1158015611e11573d6000803e3d6000fd5b50611b94925050506001600160a01b03851630612dc0565b6000611e3d846001600160a01b0316612c65565b611f84576000611e4c85613a04565b9050611ee173398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9e57600080fd5b505afa158015611eb2573d6000803e3d6000fd5b505050506040513d6020811015611ec857600080fd5b50516001600160a01b038716908563ffffffff612f8016565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b158015611f4b57600080fd5b505af1158015611f5f573d6000803e3d6000fd5b50505050611b948185611b8f30856001600160a01b0316612dc090919063ffffffff16565b611f96836001600160a01b0316612c65565b611c63576000611fa584613a04565b90506000611fb48683866107e8565b9050816001600160a01b031663db006a75826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611ffc57600080fd5b505af1158015612010573d6000803e3d6000fd5b505050508092505050610a72565b600080737079e8517594e5b21d2b9a0d17cb33f5fe2bca706001600160a01b031663d4b839926040518163ffffffff1660e01b815260040160206040518083038186803b15801561206e57600080fd5b505afa158015612082573d6000803e3d6000fd5b505050506040513d602081101561209857600080fd5b505190506120b66001600160a01b038616828563ffffffff612f8016565b806001600160a01b031663fe0291566120d7876001600160a01b0316612c65565b6120e25760006120e4565b845b604080516001600160e01b031960e085901b1681526001600160a01b03808b1660048301528916602482015260448101889052600060648201529051608480830192602092919082900301818588803b15801561214057600080fd5b505af1158015612154573d6000803e3d6000fd5b50505050506040513d602081101561216b57600080fd5b505195945050505050565b6000610a6f848484613e27565b6000610a6f84600080516020614c5a83398151915285856141d8565b6000610a6f84600080516020614c7a83398151915285856141d8565b6000610a6f84600080516020614ce683398151915285856141d8565b6000806001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e114612205576000612208565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714612233576000612236565b60035b6001600160a01b038716600080516020614ce68339815191521461225b57600061225e565b60025b6001600160a01b038816600080516020614c7a83398151915214612283576000612286565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146122c45760006122c7565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146122f25760006122f5565b60035b6001600160a01b038716600080516020614ce68339815191521461231a57600061231d565b60025b6001600160a01b038816600080516020614c7a83398151915214612342576000612345565b60015b01010160ff16905081600f0b60001480612362575080600f0b6000145b1561237257600092505050610a72565b6123a06001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c59914612444576000612447565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612472576000612475565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b038616146124a85760006124ab565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146124d65760006124d9565b60015b0160ff16905081600f0b600014806124f4575080600f0b6000145b1561250457600092505050610a72565b6125326001600160a01b038716738474c1236f0bc23830a23a41abb81b2764ba9f4f8663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151738474c1236f0bc23830a23a41abb81b2764ba9f4f92633df02124926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146125d65760006125d9565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612604576000612607565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612632576000612635565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612672576000612675565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c599146126a05760006126a3565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd847146126ce5760006126d1565b60015b010160ff16905081600f0b600014806126ed575080600f0b6000145b156126fd57600092505050610a72565b61272b6001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561120a57600080fd5b60006127d16001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff612f8016565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b15801561283b57600080fd5b505af115801561284f573d6000803e3d6000fd5b505050509392505050565b600061288a6001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff612f8016565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b15801561290957600080fd5b505af115801561291d573d6000803e3d6000fd5b505050506040513d6020811015610c0a57600080fd5b60006129636001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff612f8016565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b15801561290957600080fd5b6000806001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612a02576000612a05565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612a30576000612a33565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612a5e576000612a61565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612a9e576000612aa1565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612acc576000612acf565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612afa576000612afd565b60015b010160ff16905081600f0b60001480612b19575080600f0b6000145b15612b2957600092505050610a72565b612b576001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561120a57600080fd5b6000612bdc84848460006141ef565b509392505050565b6000612bdc84848460016141ef565b6000612bdc84848460026141ef565b600082820183811015612c5c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b0382161580612c9957506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b80612cab57612dba565b612cb484612c65565b15612d9f576001600160a01b03831633148015612cd15750803410155b612d0c5760405162461bcd60e51b815260040180806020018281038252602b815260200180614c9a602b913960400191505060405180910390fd5b6001600160a01b0382163014612d54576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015612d52573d6000803e3d6000fd5b505b80341115612d9a57336108fc612d70348463ffffffff61468616565b6040518115909202916000818181858888f19350505050158015612d98573d6000803e3d6000fd5b505b612dba565b612dba6001600160a01b03851684848463ffffffff6146c816565b50505050565b6000612dcb83612c65565b15612de157506001600160a01b03811631612c5f565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e3757600080fd5b505afa158015612e4b573d6000803e3d6000fd5b505050506040513d6020811015612e6157600080fd5b50519050612c5f565b600082612e7957506000612c5f565b82820282848281612e8657fe5b0414612c5c5760405162461bcd60e51b8152600401808060200182810382526021815260200180614cc56021913960400191505060405180910390fd5b6000612c5c83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614722565b600081612f1457506001610a72565b612f1d84612c65565b15612f5e576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612f58573d6000803e3d6000fd5b50610a72565b612f786001600160a01b038516848463ffffffff6147c416565b506001610a72565b612f8983612c65565b6130745780612fb257612fad6001600160a01b03841683600063ffffffff61481616565b613074565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561300357600080fd5b505afa158015613017573d6000803e3d6000fd5b505050506040513d602081101561302d57600080fd5b5051905081811015612dba57801561305a5761305a6001600160a01b03851684600063ffffffff61481616565b612dba6001600160a01b038516848463ffffffff61481616565b505050565b6060816001600160a01b0316836001600160a01b031614156130aa5750604080516000815260208101909152612c5f565b6130bc836001600160a01b0316612c65565b156130d95773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92505b6130eb826001600160a01b0316612c65565b156131085773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91505b6001600160a01b038316731f573d6fb3f13d689ff844b4ce37794d79a7ff1c148061314f57506001600160a01b038216731f573d6fb3f13d689ff844b4ce37794d79a7ff1c145b1561317a5760408051600380825260808201909252906020820160608038833901905050905061319c565b60408051600580825260c08201909252906020820160a0803883390190505090505b60008060007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180807f42616e636f72436f6e7665727465725265676973747279000000000000000000815250602001905060206040518083038186803b15801561321957600080fd5b505afa15801561322d573d6000803e3d6000fd5b505050506040513d602081101561324357600080fd5b505190506001600160a01b038616731f573d6fb3f13d689ff844b4ce37794d79a7ff1c1461340157600060606001600160a01b0380841690620186a090636b625ad960e11b90613294908c16612c65565b61329e578a6132b4565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160a01b039092166024830152600060448084019190915281518084039091018152606490920181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106133325780518252601f199092019160209182019101613313565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613393576040519150601f19603f3d011682016040523d82523d6000602084013e613398565b606091505b5091509150816133c15760408051600080825260208201909252905b5095505050505050612c5f565b8080602001905160208110156133d657600080fd5b505194506001600160a01b0385166133fe5760408051600080825260208201909252906133b4565b50505b6001600160a01b038516731f573d6fb3f13d689ff844b4ce37794d79a7ff1c146135b257600060606001600160a01b0380841690620186a090636b625ad960e11b9061344e908b16612c65565b613458578961346e565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160a01b039092166024830152600060448084019190915281518084039091018152606490920181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106134ec5780518252601f1990920191602091820191016134cd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d806000811461354d576040519150601f19603f3d011682016040523d82523d6000602084013e613552565b606091505b5091509150816135725760408051600080825260208201909252906133b4565b80806020019051602081101561358757600080fd5b505193506001600160a01b0384166135af5760408051600080825260208201909252906133b4565b50505b6001600160a01b038516731f573d6fb3f13d689ff844b4ce37794d79a7ff1c14156136765785846000815181106135e557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828460018151811061361357fe5b60200260200101906001600160a01b031690816001600160a01b031681525050731f573d6fb3f13d689ff844b4ce37794d79a7ff1c8460028151811061365557fe5b6001600160a01b039092166020928302919091019091015250612c5f915050565b6001600160a01b038616731f573d6fb3f13d689ff844b4ce37794d79a7ff1c141561371957731f573d6fb3f13d689ff844b4ce37794d79a7ff1c846000815181106136bd57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081846001815181106136eb57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848460028151811061365557fe5b858460008151811061372757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828460018151811061375557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050731f573d6fb3f13d689ff844b4ce37794d79a7ff1c8460028151811061379757fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081846003815181106137c557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505084846004815181106137f357fe5b6001600160a01b039092166020928302919091019091015250505092915050565b6000613828826001600160a01b0316612c65565b156138485750734ddc2d193948926d02f9b1fe9e1daa0718270ed5612c9c565b6001600160a01b038216600080516020614c7a83398151915214156138825750735d3a536e4d6dbd6114cc1ead35777bab948e3643612c9c565b6001600160a01b038216730d8775f648430679a709e98d2b0cb6250d2887ef14156138c25750736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e612c9c565b6001600160a01b038216731985365e9f78359a9b6ad760e32412f4a445e8621415613902575073158079ee67fce2f58472a96584a73c7ab9ac95c1612c9c565b6001600160a01b038216600080516020614ce6833981519152141561393c57507339aa39c021dfbae8fac545936693ac917d5e7563612c9c565b6001600160a01b038216732260fac5e5542a773aa44fbcfedf7c193bc2c599141561397c575073c11b1268c1a384e55c48c2391d8d480264a3a7f4612c9c565b6001600160a01b03821673e41d2489571d322189246dafa5ebde1f4699f49814156139bc575073b3319f5d18bc0d84dd1b4825dcde5d5f7266d407612c9c565b6001600160a01b03821673dac17f958d2ee523a2206206994597c13d831ec714156139fc575073f650c3d88d12db855b8bf7d11be6c55a4e07dcc9612c9c565b506000919050565b6000613a18826001600160a01b0316612c65565b15613a385750733a3a65aab0dd2a17e3f1947ba16138cd37d08c04612c9c565b6001600160a01b038216600080516020614c7a8339815191521415613a72575073fc1e690f61efd961294b3e1ce3313fbd8aa4f85d612c9c565b6001600160a01b038216600080516020614ce68339815191521415613aac5750739ba00d6856a4edf4665bca2c2309936572473b7e612c9c565b6001600160a01b0382167357ab1ec28d129707052df4df418d58a2d46d5f511415613aec575073625ae63000f46200499120b906716420bd059240612c9c565b6001600160a01b038216734fabb145d64652a948d72533023f6e7a623c7c531415613b2c5750736ee0f7bb50a54ab5253da0667b0dc2ee526c30a8612c9c565b6001600160a01b0382166e085d4780b73119b644ae5ecd22b3761415613b675750734da9b813057d04baef4e5800e36083717b4a0341612c9c565b6001600160a01b03821673dac17f958d2ee523a2206206994597c13d831ec71415613ba757507371fc860f7d3a592a4a98740e39db31d25db65ae8612c9c565b6001600160a01b038216730d8775f648430679a709e98d2b0cb6250d2887ef1415613be7575073e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d00612c9c565b6001600160a01b03821673dd974d5c2e2928dea5f71b9825b8b646686bd2001415613c275750739d91be44c06d373a8a226e1f3b146956083803eb612c9c565b6001600160a01b0382167380fb784b7ed66730e8b1dbd9820afd29931aab031415613c675750737d2d3688df45ce7c552e19c27e007673da9204b8612c9c565b6001600160a01b03821673514910771af9ca656af840dff83e8264ecf986ca1415613ca7575073a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f84612c9c565b6001600160a01b038216730f5d2fb29fb7d3cfee444a200298f468908cc9421415613ce75750736fce4a401b6b80ace52baaefe4421bd188e76f6f612c9c565b6001600160a01b038216739f8f72aa9304c8b593d555f12ef6589cc3a579a21415613d275750737deb5e830be29f91e298ba5ff1356bb7f8146998612c9c565b6001600160a01b038216731985365e9f78359a9b6ad760e32412f4a445e8621415613d6757507371010a9d003445ac60c4e6a7017c1e89a477b438612c9c565b6001600160a01b03821673c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f1415613da7575073328c4c80bc7aca0834db37e6600a6c49e12da4de612c9c565b6001600160a01b038216732260fac5e5542a773aa44fbcfedf7c193bc2c5991415613de7575073fc4b8ed459e00e5400be803a9bb3954234fd50e3612c9c565b6001600160a01b03821673e41d2489571d322189246dafa5ebde1f4699f49814156139fc5750736fb0855c404e09c47c3fbca25f08d4e41f9f062f612c9c565b6000613e3b846001600160a01b0316612c65565b15613ea357600080516020614c5a8339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e8957600080fd5b505af1158015613e9d573d6000803e3d6000fd5b50505050505b6000613eb7856001600160a01b0316612c65565b613ec15784613ed1565b600080516020614c5a8339815191525b90506000613ee7856001600160a01b0316612c65565b613ef15784613f01565b600080516020614c5a8339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b158015613f6957600080fd5b505afa158015613f7d573d6000803e3d6000fd5b505050506040513d6020811015613f9357600080fd5b50519050613fb26001600160a01b03821684848863ffffffff61492916565b9350613fce6001600160a01b038416828763ffffffff612f0516565b50816001600160a01b0316836001600160a01b03161015614067576040805163022c0d9f60e01b815260006004820181905260248201879052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b15801561404a57600080fd5b505af115801561405e573d6000803e3d6000fd5b505050506140e1565b6040805163022c0d9f60e01b815260048101869052600060248201819052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b1580156140c857600080fd5b505af11580156140dc573d6000803e3d6000fd5b505050505b6140f3866001600160a01b0316612c65565b156141ce57604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561414b57600080fd5b505afa15801561415f573d6000803e3d6000fd5b505050506040513d602081101561417557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156141b557600080fd5b505af11580156141c9573d6000803e3d6000fd5b505050505b5050509392505050565b600061108784846141ea888887613e27565b613e27565b600060607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc4361421f6001600160a01b038916612c65565b6142295787614239565b600080516020614c5a8339815191525b61424b886001600160a01b0316612c65565b6142555787614265565b600080516020614c5a8339815191525b866001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b1580156142cf57600080fd5b505afa1580156142e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561430c57600080fd5b810190808051604051939291908464010000000082111561432c57600080fd5b90830190602082018581111561434157600080fd5b825186602082028301116401000000008211171561435e57600080fd5b82525081516020918201928201910280838360005b8381101561438b578181015183820152602001614373565b5050505090500160405250505090506143ac866001600160a01b0316612c65565b1561441457600080516020614c5a8339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156143fa57600080fd5b505af115801561440e573d6000803e3d6000fd5b50505050505b61446e81848151811061442357fe5b60200260200101518561443e896001600160a01b0316612c65565b6144485787614458565b600080516020614c5a8339815191525b6001600160a01b0316919063ffffffff612f8016565b80838151811061447a57fe5b60200260200101516001600160a01b0316638201aa3f6144a2886001600160a01b0316612c65565b6144ac57876144bc565b600080516020614c5a8339815191525b866144cf896001600160a01b0316612c65565b6144d957886144e9565b600080516020614c5a8339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b15801561456357600080fd5b505af1158015614577573d6000803e3d6000fd5b505050506040513d604081101561458d57600080fd5b506145a290506001600160a01b038616612c65565b1561467d57604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156145fa57600080fd5b505afa15801561460e573d6000803e3d6000fd5b505050506040513d602081101561462457600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561466457600080fd5b505af1158015614678573d6000803e3d6000fd5b505050505b50949350505050565b6000612c5c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506149e0565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612dba908590614a3a565b600081836147ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561477357818101518382015260200161475b565b50505050905090810190601f1680156147a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816147ba57fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613074908490614a3a565b80158061489c575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561486e57600080fd5b505afa158015614882573d6000803e3d6000fd5b505050506040513d602081101561489857600080fd5b5051155b6148d75760405162461bcd60e51b8152600401808060200182810382526036815260200180614d566036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613074908490614a3a565b6000806149456001600160a01b0386168763ffffffff612dc016565b905060006149626001600160a01b0386168863ffffffff612dc016565b90506000614978856103e563ffffffff612e6a16565b9050600061498c828463ffffffff612e6a16565b905060006149b2836149a6876103e863ffffffff612e6a16565b9063ffffffff612c0216565b905080156149cf576149ca828263ffffffff612ec316565b6149d2565b60005b9a9950505050505050505050565b60008184841115614a325760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561477357818101518382015260200161475b565b505050900390565b614a4c826001600160a01b0316614bf2565b614a9d576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614adb5780518252601f199092019160209182019101614abc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614b3d576040519150601f19603f3d011682016040523d82523d6000602084013e614b42565b606091505b509150915081614b99576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115612dba57808060200190516020811015614bb557600080fd5b5051612dba5760405162461bcd60e51b815260040180806020018281038252602a815260200180614d2c602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614c2657508115155b949350505050565b604051806103600160405280601b905b614c57815260200190600190039081614c3e5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a7231582011f96d9b4dc5bb090d921b8c3f4ea696379369f1bd7e9a75b0a1c639a86cc00a64736f6c634300051100320000000000000000000000004c9327ad39d41bb6c39c300fe6742914f6e9e6ea
Deployed Bytecode
0x60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed951461028b575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102bc565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102df565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610279600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a08101608082013564010000000081111561020557600080fd5b82018360208201111561021757600080fd5b8035906020019184602083028401116401000000008311171561023957600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610438915050565b60408051918252519081900360200190f35b34801561029757600080fd5b506102a06107d9565b604080516001600160a01b039092168252519081900360200190f35b600060606102cf878787878760006102df565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035257600080fd5b505afa158015610366573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038f57600080fd5b815160208301516040808501805191519395929483019291846401000000008211156103ba57600080fd5b9083019060208201858111156103cf57600080fd5b82518660208202830111640100000000821117156103ec57600080fd5b82525081516020918201928201910280838360005b83811015610419578181015183820152602001610401565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b0316141561045b5750836107cf565b610463614c2e565b6040518061036001604052806107e88152602001610a798152602001610c148152602001610dbf8152602001611090815260200161122b815260200161140c815260200161164181526020016118808152602001611abf8152602001611c6d8152602001611e29815260200161201e81526020016121768152602001612183815260200161219f81526020016121bb81526020016121d7815260200161241681526020016125a881526020016127a1815260200161285a815260200161293381526020016129d48152602001612bcd8152602001612be48152602001612bf38152509050601b845111156105885760405162461bcd60e51b8152600401808060200182810382526042815260200180614d8c6042913960600191505060405180910390fd5b600080805b86518110156105e65760008782815181106105a457fe5b602002602001015111156105de576105d88782815181106105c157fe5b602002602001015184612c0290919063ffffffff16565b92508091505b60010161058d565b5081610646576105fe8a6001600160a01b0316612c65565b1561063b5760405133903480156108fc02916000818181858888f1935050505015801561062f573d6000803e3d6000fd5b503493505050506107cf565b8793505050506107cf565b6106616001600160a01b038b1633308b63ffffffff612ca116565b600061067c6001600160a01b038c163063ffffffff612dc016565b905060005b875181101561071f5787818151811061069657fe5b6020026020010151600014156106ab57610717565b60006106e3856106d78b85815181106106c057fe5b60200260200101518e612e6a90919063ffffffff16565b9063ffffffff612ec316565b9050838214156106f05750815b80830392506107148d8d838986601b811061070757fe5b602002015163ffffffff16565b50505b600101610681565b506107396001600160a01b038b163063ffffffff612dc016565b94508785101561077a5760405162461bcd60e51b8152600401808060200182810382526026815260200180614d066026913960400191505060405180910390fd5b6107946001600160a01b038b16338763ffffffff612f0516565b506107c9336107b26001600160a01b038e163063ffffffff612dc016565b6001600160a01b038e16919063ffffffff612f0516565b50505050505b9695505050505050565b6000546001600160a01b031681565b6000816107fd6001600160a01b038616612c65565b61093d57604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561085f57600080fd5b505afa158015610873573d6000803e3d6000fd5b505050506040513d602081101561088957600080fd5b505190506001600160a01b0381161561093b576108b66001600160a01b038716828463ffffffff612f8016565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561090c57600080fd5b505af1158015610920573d6000803e3d6000fd5b505050506040513d602081101561093657600080fd5b505191505b505b61094f846001600160a01b0316612c65565b610a6f57604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109b157600080fd5b505afa1580156109c5573d6000803e3d6000fd5b505050506040513d60208110156109db57600080fd5b505190506001600160a01b03811615610a6d57806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a3d57600080fd5b505af1158015610a51573d6000803e3d6000fd5b50505050506040513d6020811015610a6857600080fd5b505191505b505b90505b9392505050565b6000610aa96001600160a01b03851673818e6fecd516ecc3849daf6845e3ec868087b7558463ffffffff612f8016565b73818e6fecd516ecc3849daf6845e3ec868087b7556329589f61610ad56001600160a01b038716612c65565b610ae0576000610ae2565b835b610af4876001600160a01b0316612c65565b610afe5786610b14565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b85610b27886001600160a01b0316612c65565b610b315787610b47565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e088901b1681526001600160a01b039485166004820152602481019390935292166044820152306064820152600160ff1b6084820152600060a48201819052734d37f28d2db99e8d35a6c725a5f1749a085850a360c483015261010060e4830152610104820152905161014480830192602092919082900301818588803b158015610bdf57600080fd5b505af1158015610bf3573d6000803e3d6000fd5b50505050506040513d6020811015610c0a57600080fd5b5051949350505050565b6000807352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610c7f57600080fd5b505afa158015610c93573d6000803e3d6000fd5b505050506040513d6020811015610ca957600080fd5b505190506060610cb98686613079565b9050610cd56001600160a01b038716838663ffffffff612f8016565b816001600160a01b031663f3898a97610cf6886001600160a01b0316612c65565b610d01576000610d03565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610d62578181015183820152602001610d4a565b505050509050019450505050506020604051808303818588803b158015610d8857600080fd5b505af1158015610d9c573d6000803e3d6000fd5b50505050506040513d6020811015610db357600080fd5b50519695505050505050565b6000610dd3846001600160a01b0316612c65565b15610e3b57600080516020614c5a8339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e2157600080fd5b505af1158015610e35573d6000803e3d6000fd5b50505050505b6000610e4f856001600160a01b0316612c65565b610e595784610e69565b600080516020614c5a8339815191525b9050610e996001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff612f8016565b600073794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610ec76001600160a01b038916612c65565b610ed15787610ee1565b600080516020614c5a8339815191525b86610ef4896001600160a01b0316612c65565b610efe5788610f0e565b600080516020614c5a8339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610f6c57600080fd5b505af1158015610f80573d6000803e3d6000fd5b505050506040513d6020811015610f9657600080fd5b50519050610fac6001600160a01b038616612c65565b1561108757604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561100457600080fd5b505afa158015611018573d6000803e3d6000fd5b505050506040513d602081101561102e57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561106e57600080fd5b505af1158015611082573d6000803e3d6000fd5b505050505b95945050505050565b6000806001600160a01b038516600080516020614ce6833981519152146110b85760006110bb565b60025b6001600160a01b038616600080516020614c7a833981519152146110e05760006110e3565b60015b0160ff1690506000600080516020614ce68339815191526001600160a01b03861614611110576000611113565b60025b6001600160a01b038616600080516020614c7a8339815191521461113857600061113b565b60015b0160ff16905081600f0b60001480611156575080600f0b6000145b1561116657600092505050610a72565b6111946001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b505af115801561121e573d6000803e3d6000fd5b5050505050509392505050565b6000806001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec71461125957600061125c565b60035b6001600160a01b038616600080516020614ce683398151915214611281576000611284565b60025b6001600160a01b038716600080516020614c7a833981519152146112a95760006112ac565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b0316146112e95760006112ec565b60035b6001600160a01b038616600080516020614ce683398151915214611311576000611314565b60025b6001600160a01b038716600080516020614c7a8339815191521461133957600061133c565b60015b010160ff16905081600f0b60001480611358575080600f0b6000145b1561136857600092505050610a72565b6113966001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b0385166e085d4780b73119b644ae5ecd22b37614611435576000611438565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611463576000611466565b60035b6001600160a01b038716600080516020614ce68339815191521461148b57600061148e565b60025b6001600160a01b038816600080516020614c7a833981519152146114b35760006114b6565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b0316146114ef5760006114f2565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461151d576000611520565b60035b6001600160a01b038716600080516020614ce683398151915214611545576000611548565b60025b6001600160a01b038816600080516020614c7a8339815191521461156d576000611570565b60015b01010160ff16905081600f0b6000148061158d575080600f0b6000145b1561159d57600092505050610a72565b6115cb6001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c531461166f576000611672565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461169d5760006116a0565b60035b6001600160a01b038716600080516020614ce6833981519152146116c55760006116c8565b60025b6001600160a01b038816600080516020614c7a833981519152146116ed5760006116f0565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b03161461172e576000611731565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461175c57600061175f565b60035b6001600160a01b038716600080516020614ce683398151915214611784576000611787565b60025b6001600160a01b038816600080516020614c7a833981519152146117ac5760006117af565b60015b01010160ff16905081600f0b600014806117cc575080600f0b6000145b156117dc57600092505050610a72565b61180a6001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f51146118ae5760006118b1565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146118dc5760006118df565b60035b6001600160a01b038716600080516020614ce683398151915214611904576000611907565b60025b6001600160a01b038816600080516020614c7a8339815191521461192c57600061192f565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b03161461196d576000611970565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461199b57600061199e565b60035b6001600160a01b038716600080516020614ce6833981519152146119c35760006119c6565b60025b6001600160a01b038816600080516020614c7a833981519152146119eb5760006119ee565b60015b01010160ff16905081600f0b60001480611a0b575080600f0b6000145b15611a1b57600092505050610a72565b611a496001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000611ad3846001600160a01b0316612c65565b611b9c576000611ae285613814565b9050611afe6001600160a01b038616828563ffffffff612f8016565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611b4457600080fd5b505af1158015611b58573d6000803e3d6000fd5b505050506040513d6020811015611b6e57600080fd5b50611b9490508185611b8f6001600160a01b0383163063ffffffff612dc016565b6107e8565b915050610a72565b611bae836001600160a01b0316612c65565b611c63576000611bbd84613814565b90506000611bcc8683866107e8565b9050816001600160a01b031663db006a75826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c1457600080fd5b505af1158015611c28573d6000803e3d6000fd5b505050506040513d6020811015611c3e57600080fd5b50611c5a90506001600160a01b0386163063ffffffff612dc016565b92505050610a72565b5060009392505050565b60006001600160a01b038416600080516020614c7a8339815191521415611d6057611cbc6001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff612f8016565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611d1557600080fd5b505af1158015611d29573d6000803e3d6000fd5b50611d5992507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611b8f823063ffffffff612dc016565b9050610a72565b6001600160a01b038316600080516020614c7a8339815191521415611c63576000611da0857306af07097c9eeb7fd685c692751d5c66db49c215856107e8565b6040805163ef693bed60e01b81523060048201526024810183905290519192507306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed9160448082019260009290919082900301818387803b158015611dfd57600080fd5b505af1158015611e11573d6000803e3d6000fd5b50611b94925050506001600160a01b03851630612dc0565b6000611e3d846001600160a01b0316612c65565b611f84576000611e4c85613a04565b9050611ee173398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b158015611e9e57600080fd5b505afa158015611eb2573d6000803e3d6000fd5b505050506040513d6020811015611ec857600080fd5b50516001600160a01b038716908563ffffffff612f8016565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b158015611f4b57600080fd5b505af1158015611f5f573d6000803e3d6000fd5b50505050611b948185611b8f30856001600160a01b0316612dc090919063ffffffff16565b611f96836001600160a01b0316612c65565b611c63576000611fa584613a04565b90506000611fb48683866107e8565b9050816001600160a01b031663db006a75826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611ffc57600080fd5b505af1158015612010573d6000803e3d6000fd5b505050508092505050610a72565b600080737079e8517594e5b21d2b9a0d17cb33f5fe2bca706001600160a01b031663d4b839926040518163ffffffff1660e01b815260040160206040518083038186803b15801561206e57600080fd5b505afa158015612082573d6000803e3d6000fd5b505050506040513d602081101561209857600080fd5b505190506120b66001600160a01b038616828563ffffffff612f8016565b806001600160a01b031663fe0291566120d7876001600160a01b0316612c65565b6120e25760006120e4565b845b604080516001600160e01b031960e085901b1681526001600160a01b03808b1660048301528916602482015260448101889052600060648201529051608480830192602092919082900301818588803b15801561214057600080fd5b505af1158015612154573d6000803e3d6000fd5b50505050506040513d602081101561216b57600080fd5b505195945050505050565b6000610a6f848484613e27565b6000610a6f84600080516020614c5a83398151915285856141d8565b6000610a6f84600080516020614c7a83398151915285856141d8565b6000610a6f84600080516020614ce683398151915285856141d8565b6000806001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e114612205576000612208565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714612233576000612236565b60035b6001600160a01b038716600080516020614ce68339815191521461225b57600061225e565b60025b6001600160a01b038816600080516020614c7a83398151915214612283576000612286565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146122c45760006122c7565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146122f25760006122f5565b60035b6001600160a01b038716600080516020614ce68339815191521461231a57600061231d565b60025b6001600160a01b038816600080516020614c7a83398151915214612342576000612345565b60015b01010160ff16905081600f0b60001480612362575080600f0b6000145b1561237257600092505050610a72565b6123a06001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff612f8016565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c59914612444576000612447565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612472576000612475565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b038616146124a85760006124ab565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146124d65760006124d9565b60015b0160ff16905081600f0b600014806124f4575080600f0b6000145b1561250457600092505050610a72565b6125326001600160a01b038716738474c1236f0bc23830a23a41abb81b2764ba9f4f8663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151738474c1236f0bc23830a23a41abb81b2764ba9f4f92633df02124926084808201939182900301818387803b15801561120a57600080fd5b6000806001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146125d65760006125d9565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612604576000612607565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612632576000612635565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612672576000612675565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c599146126a05760006126a3565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd847146126ce5760006126d1565b60015b010160ff16905081600f0b600014806126ed575080600f0b6000145b156126fd57600092505050610a72565b61272b6001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561120a57600080fd5b60006127d16001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff612f8016565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b15801561283b57600080fd5b505af115801561284f573d6000803e3d6000fd5b505050509392505050565b600061288a6001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff612f8016565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b15801561290957600080fd5b505af115801561291d573d6000803e3d6000fd5b505050506040513d6020811015610c0a57600080fd5b60006129636001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff612f8016565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b15801561290957600080fd5b6000806001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612a02576000612a05565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612a30576000612a33565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612a5e576000612a61565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612a9e576000612aa1565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612acc576000612acf565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612afa576000612afd565b60015b010160ff16905081600f0b60001480612b19575080600f0b6000145b15612b2957600092505050610a72565b612b576001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff612f8016565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561120a57600080fd5b6000612bdc84848460006141ef565b509392505050565b6000612bdc84848460016141ef565b6000612bdc84848460026141ef565b600082820183811015612c5c576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b0382161580612c9957506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b80612cab57612dba565b612cb484612c65565b15612d9f576001600160a01b03831633148015612cd15750803410155b612d0c5760405162461bcd60e51b815260040180806020018281038252602b815260200180614c9a602b913960400191505060405180910390fd5b6001600160a01b0382163014612d54576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015612d52573d6000803e3d6000fd5b505b80341115612d9a57336108fc612d70348463ffffffff61468616565b6040518115909202916000818181858888f19350505050158015612d98573d6000803e3d6000fd5b505b612dba565b612dba6001600160a01b03851684848463ffffffff6146c816565b50505050565b6000612dcb83612c65565b15612de157506001600160a01b03811631612c5f565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e3757600080fd5b505afa158015612e4b573d6000803e3d6000fd5b505050506040513d6020811015612e6157600080fd5b50519050612c5f565b600082612e7957506000612c5f565b82820282848281612e8657fe5b0414612c5c5760405162461bcd60e51b8152600401808060200182810382526021815260200180614cc56021913960400191505060405180910390fd5b6000612c5c83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614722565b600081612f1457506001610a72565b612f1d84612c65565b15612f5e576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612f58573d6000803e3d6000fd5b50610a72565b612f786001600160a01b038516848463ffffffff6147c416565b506001610a72565b612f8983612c65565b6130745780612fb257612fad6001600160a01b03841683600063ffffffff61481616565b613074565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561300357600080fd5b505afa158015613017573d6000803e3d6000fd5b505050506040513d602081101561302d57600080fd5b5051905081811015612dba57801561305a5761305a6001600160a01b03851684600063ffffffff61481616565b612dba6001600160a01b038516848463ffffffff61481616565b505050565b6060816001600160a01b0316836001600160a01b031614156130aa5750604080516000815260208101909152612c5f565b6130bc836001600160a01b0316612c65565b156130d95773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92505b6130eb826001600160a01b0316612c65565b156131085773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91505b6001600160a01b038316731f573d6fb3f13d689ff844b4ce37794d79a7ff1c148061314f57506001600160a01b038216731f573d6fb3f13d689ff844b4ce37794d79a7ff1c145b1561317a5760408051600380825260808201909252906020820160608038833901905050905061319c565b60408051600580825260c08201909252906020820160a0803883390190505090505b60008060007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180807f42616e636f72436f6e7665727465725265676973747279000000000000000000815250602001905060206040518083038186803b15801561321957600080fd5b505afa15801561322d573d6000803e3d6000fd5b505050506040513d602081101561324357600080fd5b505190506001600160a01b038616731f573d6fb3f13d689ff844b4ce37794d79a7ff1c1461340157600060606001600160a01b0380841690620186a090636b625ad960e11b90613294908c16612c65565b61329e578a6132b4565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160a01b039092166024830152600060448084019190915281518084039091018152606490920181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106133325780518252601f199092019160209182019101613313565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613393576040519150601f19603f3d011682016040523d82523d6000602084013e613398565b606091505b5091509150816133c15760408051600080825260208201909252905b5095505050505050612c5f565b8080602001905160208110156133d657600080fd5b505194506001600160a01b0385166133fe5760408051600080825260208201909252906133b4565b50505b6001600160a01b038516731f573d6fb3f13d689ff844b4ce37794d79a7ff1c146135b257600060606001600160a01b0380841690620186a090636b625ad960e11b9061344e908b16612c65565b613458578961346e565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160a01b039092166024830152600060448084019190915281518084039091018152606490920181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106134ec5780518252601f1990920191602091820191016134cd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d806000811461354d576040519150601f19603f3d011682016040523d82523d6000602084013e613552565b606091505b5091509150816135725760408051600080825260208201909252906133b4565b80806020019051602081101561358757600080fd5b505193506001600160a01b0384166135af5760408051600080825260208201909252906133b4565b50505b6001600160a01b038516731f573d6fb3f13d689ff844b4ce37794d79a7ff1c14156136765785846000815181106135e557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828460018151811061361357fe5b60200260200101906001600160a01b031690816001600160a01b031681525050731f573d6fb3f13d689ff844b4ce37794d79a7ff1c8460028151811061365557fe5b6001600160a01b039092166020928302919091019091015250612c5f915050565b6001600160a01b038616731f573d6fb3f13d689ff844b4ce37794d79a7ff1c141561371957731f573d6fb3f13d689ff844b4ce37794d79a7ff1c846000815181106136bd57fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081846001815181106136eb57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050848460028151811061365557fe5b858460008151811061372757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050828460018151811061375557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050731f573d6fb3f13d689ff844b4ce37794d79a7ff1c8460028151811061379757fe5b60200260200101906001600160a01b031690816001600160a01b03168152505081846003815181106137c557fe5b60200260200101906001600160a01b031690816001600160a01b03168152505084846004815181106137f357fe5b6001600160a01b039092166020928302919091019091015250505092915050565b6000613828826001600160a01b0316612c65565b156138485750734ddc2d193948926d02f9b1fe9e1daa0718270ed5612c9c565b6001600160a01b038216600080516020614c7a83398151915214156138825750735d3a536e4d6dbd6114cc1ead35777bab948e3643612c9c565b6001600160a01b038216730d8775f648430679a709e98d2b0cb6250d2887ef14156138c25750736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e612c9c565b6001600160a01b038216731985365e9f78359a9b6ad760e32412f4a445e8621415613902575073158079ee67fce2f58472a96584a73c7ab9ac95c1612c9c565b6001600160a01b038216600080516020614ce6833981519152141561393c57507339aa39c021dfbae8fac545936693ac917d5e7563612c9c565b6001600160a01b038216732260fac5e5542a773aa44fbcfedf7c193bc2c599141561397c575073c11b1268c1a384e55c48c2391d8d480264a3a7f4612c9c565b6001600160a01b03821673e41d2489571d322189246dafa5ebde1f4699f49814156139bc575073b3319f5d18bc0d84dd1b4825dcde5d5f7266d407612c9c565b6001600160a01b03821673dac17f958d2ee523a2206206994597c13d831ec714156139fc575073f650c3d88d12db855b8bf7d11be6c55a4e07dcc9612c9c565b506000919050565b6000613a18826001600160a01b0316612c65565b15613a385750733a3a65aab0dd2a17e3f1947ba16138cd37d08c04612c9c565b6001600160a01b038216600080516020614c7a8339815191521415613a72575073fc1e690f61efd961294b3e1ce3313fbd8aa4f85d612c9c565b6001600160a01b038216600080516020614ce68339815191521415613aac5750739ba00d6856a4edf4665bca2c2309936572473b7e612c9c565b6001600160a01b0382167357ab1ec28d129707052df4df418d58a2d46d5f511415613aec575073625ae63000f46200499120b906716420bd059240612c9c565b6001600160a01b038216734fabb145d64652a948d72533023f6e7a623c7c531415613b2c5750736ee0f7bb50a54ab5253da0667b0dc2ee526c30a8612c9c565b6001600160a01b0382166e085d4780b73119b644ae5ecd22b3761415613b675750734da9b813057d04baef4e5800e36083717b4a0341612c9c565b6001600160a01b03821673dac17f958d2ee523a2206206994597c13d831ec71415613ba757507371fc860f7d3a592a4a98740e39db31d25db65ae8612c9c565b6001600160a01b038216730d8775f648430679a709e98d2b0cb6250d2887ef1415613be7575073e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d00612c9c565b6001600160a01b03821673dd974d5c2e2928dea5f71b9825b8b646686bd2001415613c275750739d91be44c06d373a8a226e1f3b146956083803eb612c9c565b6001600160a01b0382167380fb784b7ed66730e8b1dbd9820afd29931aab031415613c675750737d2d3688df45ce7c552e19c27e007673da9204b8612c9c565b6001600160a01b03821673514910771af9ca656af840dff83e8264ecf986ca1415613ca7575073a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f84612c9c565b6001600160a01b038216730f5d2fb29fb7d3cfee444a200298f468908cc9421415613ce75750736fce4a401b6b80ace52baaefe4421bd188e76f6f612c9c565b6001600160a01b038216739f8f72aa9304c8b593d555f12ef6589cc3a579a21415613d275750737deb5e830be29f91e298ba5ff1356bb7f8146998612c9c565b6001600160a01b038216731985365e9f78359a9b6ad760e32412f4a445e8621415613d6757507371010a9d003445ac60c4e6a7017c1e89a477b438612c9c565b6001600160a01b03821673c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f1415613da7575073328c4c80bc7aca0834db37e6600a6c49e12da4de612c9c565b6001600160a01b038216732260fac5e5542a773aa44fbcfedf7c193bc2c5991415613de7575073fc4b8ed459e00e5400be803a9bb3954234fd50e3612c9c565b6001600160a01b03821673e41d2489571d322189246dafa5ebde1f4699f49814156139fc5750736fb0855c404e09c47c3fbca25f08d4e41f9f062f612c9c565b6000613e3b846001600160a01b0316612c65565b15613ea357600080516020614c5a8339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e8957600080fd5b505af1158015613e9d573d6000803e3d6000fd5b50505050505b6000613eb7856001600160a01b0316612c65565b613ec15784613ed1565b600080516020614c5a8339815191525b90506000613ee7856001600160a01b0316612c65565b613ef15784613f01565b600080516020614c5a8339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b158015613f6957600080fd5b505afa158015613f7d573d6000803e3d6000fd5b505050506040513d6020811015613f9357600080fd5b50519050613fb26001600160a01b03821684848863ffffffff61492916565b9350613fce6001600160a01b038416828763ffffffff612f0516565b50816001600160a01b0316836001600160a01b03161015614067576040805163022c0d9f60e01b815260006004820181905260248201879052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b15801561404a57600080fd5b505af115801561405e573d6000803e3d6000fd5b505050506140e1565b6040805163022c0d9f60e01b815260048101869052600060248201819052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b1580156140c857600080fd5b505af11580156140dc573d6000803e3d6000fd5b505050505b6140f3866001600160a01b0316612c65565b156141ce57604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561414b57600080fd5b505afa15801561415f573d6000803e3d6000fd5b505050506040513d602081101561417557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156141b557600080fd5b505af11580156141c9573d6000803e3d6000fd5b505050505b5050509392505050565b600061108784846141ea888887613e27565b613e27565b600060607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc4361421f6001600160a01b038916612c65565b6142295787614239565b600080516020614c5a8339815191525b61424b886001600160a01b0316612c65565b6142555787614265565b600080516020614c5a8339815191525b866001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b1580156142cf57600080fd5b505afa1580156142e3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561430c57600080fd5b810190808051604051939291908464010000000082111561432c57600080fd5b90830190602082018581111561434157600080fd5b825186602082028301116401000000008211171561435e57600080fd5b82525081516020918201928201910280838360005b8381101561438b578181015183820152602001614373565b5050505090500160405250505090506143ac866001600160a01b0316612c65565b1561441457600080516020614c5a8339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156143fa57600080fd5b505af115801561440e573d6000803e3d6000fd5b50505050505b61446e81848151811061442357fe5b60200260200101518561443e896001600160a01b0316612c65565b6144485787614458565b600080516020614c5a8339815191525b6001600160a01b0316919063ffffffff612f8016565b80838151811061447a57fe5b60200260200101516001600160a01b0316638201aa3f6144a2886001600160a01b0316612c65565b6144ac57876144bc565b600080516020614c5a8339815191525b866144cf896001600160a01b0316612c65565b6144d957886144e9565b600080516020614c5a8339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b15801561456357600080fd5b505af1158015614577573d6000803e3d6000fd5b505050506040513d604081101561458d57600080fd5b506145a290506001600160a01b038616612c65565b1561467d57604080516370a0823160e01b81523060048201529051600080516020614c5a83398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156145fa57600080fd5b505afa15801561460e573d6000803e3d6000fd5b505050506040513d602081101561462457600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561466457600080fd5b505af1158015614678573d6000803e3d6000fd5b505050505b50949350505050565b6000612c5c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506149e0565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612dba908590614a3a565b600081836147ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561477357818101518382015260200161475b565b50505050905090810190601f1680156147a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816147ba57fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613074908490614a3a565b80158061489c575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561486e57600080fd5b505afa158015614882573d6000803e3d6000fd5b505050506040513d602081101561489857600080fd5b5051155b6148d75760405162461bcd60e51b8152600401808060200182810382526036815260200180614d566036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613074908490614a3a565b6000806149456001600160a01b0386168763ffffffff612dc016565b905060006149626001600160a01b0386168863ffffffff612dc016565b90506000614978856103e563ffffffff612e6a16565b9050600061498c828463ffffffff612e6a16565b905060006149b2836149a6876103e863ffffffff612e6a16565b9063ffffffff612c0216565b905080156149cf576149ca828263ffffffff612ec316565b6149d2565b60005b9a9950505050505050505050565b60008184841115614a325760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561477357818101518382015260200161475b565b505050900390565b614a4c826001600160a01b0316614bf2565b614a9d576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614adb5780518252601f199092019160209182019101614abc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614b3d576040519150601f19603f3d011682016040523d82523d6000602084013e614b42565b606091505b509150915081614b99576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115612dba57808060200190516020811015614bb557600080fd5b5051612dba5760405162461bcd60e51b815260040180806020018281038252602a815260200180614d2c602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614c2657508115155b949350505050565b604051806103600160405280601b905b614c57815260200190600190039081614c3e5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a7231582011f96d9b4dc5bb090d921b8c3f4ea696379369f1bd7e9a75b0a1c639a86cc00a64736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004c9327ad39d41bb6c39c300fe6742914f6e9e6ea
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x4C9327aD39d41Bb6c39C300FE6742914F6e9e6Ea
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004c9327ad39d41bb6c39c300fe6742914f6e9e6ea
Deployed Bytecode Sourcemap
100358:20777:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100661:10;100675:9;100661:23;;100653:32;;;;;;100358:20777;100701:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;100701:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;100701:515:0;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;100701:515:0;;;;;;;;;;;;;;;;;;101224:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;101224:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;101224:627:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;101224:627:0;;;;;;;;;;;;;;;;;;;101859:2853;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;101859:2853:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;101859:2853:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;101859:2853:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;101859:2853:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;101859:2853:0;;-1:-1:-1;;101859:2853:0;;;-1:-1:-1;101859:2853:0;;-1:-1:-1;;101859:2853:0:i;:::-;;;;;;;;;;;;;;;;100410:33;;8:9:-1;5:2;;;30:1;27;20:12;5:2;100410:33:0;;;:::i;:::-;;;;-1:-1:-1;;;;;100410:33:0;;;;;;;;;;;;;;100701:515;100923:20;100958:29;101048:160;101087:9;101111;101135:6;101156:5;101176;101196:1;101048:24;:160::i;:::-;101015:193;;;;-1:-1:-1;100701:515:0;;-1:-1:-1;;;;;;;100701:515:0:o;101224:627::-;101502:20;101641:12;;:202;;;-1:-1:-1;;;101641:202:0;;-1:-1:-1;;;;;101641:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101502:20;;101577:29;;101641:12;;:37;;:202;;;;;101502:20;;101641:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;101641:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;101641:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;101641:202:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;101641:202:0;;;;;;;;;;;;;;;;;;;;;;;19:11:-1;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;101641:202:0;;421:4:-1;412:14;;;;101641:202:0;;;;;412:14:-1;101641:202:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;101641:202:0;;;;;;;;;;;101634:209;;;;;;101224:627;;;;;;;;;;:::o;101859:2853::-;102113:20;102163:9;-1:-1:-1;;;;;102150:22:0;:9;-1:-1:-1;;;;;102150:22:0;;102146:68;;;-1:-1:-1;102196:6:0;102189:13;;102146:68;102226:77;;:::i;:::-;:944;;;;;;;;102321:14;102226:944;;;;102350:12;102226:944;;;;102377:13;102226:944;;;;102405:12;102226:944;;;;102432:20;102226:944;;;;102467:16;102226:944;;;;102498:13;102226:944;;;;102526:19;102226:944;;;;102560:21;102226:944;;;;102596:22;102226:944;;;;102633:18;102226:944;;;;102666:18;102226:944;;;;102699:16;102226:944;;;;102730:16;102226:944;;;;102761:19;102226:944;;;;102795:19;102226:944;;;;102829:20;102226:944;;;;102864:15;102226:944;;;;102894:18;102226:944;;;;102927:16;102226:944;;;;102958:17;102226:944;;;;102990:12;102226:944;;;;103017:18;102226:944;;;;103050:16;102226:944;;;;103081:16;102226:944;;;;103112:16;102226:944;;;;103143:16;102226:944;;;;;103214:15;103191:12;:19;:38;;103183:117;;;;-1:-1:-1;;;103183:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103313:13;;;103380:206;103401:12;:19;103397:1;:23;103380:206;;;103464:1;103446:12;103459:1;103446:15;;;;;;;;;;;;;;:19;103442:133;;;103494:26;103504:12;103517:1;103504:15;;;;;;;;;;;;;;103494:5;:9;;:26;;;;:::i;:::-;103486:34;;103558:1;103539:20;;103442:133;103422:3;;103380:206;;;-1:-1:-1;103602:10:0;103598:193;;103633:17;:9;-1:-1:-1;;;;;103633:15:0;;:17::i;:::-;103629:123;;;103671:30;;:10;;103691:9;103671:30;;;;;;;;;103691:9;103671:10;:30;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;103671:30:0;103727:9;103720:16;;;;;;;103629:123;103773:6;103766:13;;;;;;;103598:193;103803:66;-1:-1:-1;;;;;103803:31:0;;103835:10;103855:4;103862:6;103803:66;:31;:66;:::i;:::-;103880:23;103906:43;-1:-1:-1;;;;;103906:28:0;;103943:4;103906:43;:28;:43;:::i;:::-;103880:69;-1:-1:-1;103967:6:0;103962:426;103983:12;:19;103979:1;:23;103962:426;;;104028:12;104041:1;104028:15;;;;;;;;;;;;;;104047:1;104028:20;104024:69;;;104069:8;;104024:69;104109:18;104130:38;104162:5;104130:27;104141:12;104154:1;104141:15;;;;;;;;;;;;;;104130:6;:10;;:27;;;;:::i;:::-;:31;:38;:31;:38;:::i;:::-;104109:59;;104192:16;104187:1;:21;104183:90;;;-1:-1:-1;104242:15:0;104183:90;104306:10;104287:29;;;;104331:45;104343:9;104354;104365:10;104331:8;104340:1;104331:11;;;;;;;;;;;:45;;:::i;:::-;;103962:426;;104004:3;;103962:426;;;-1:-1:-1;104415:43:0;-1:-1:-1;;;;;104415:28:0;;104452:4;104415:43;:28;:43;:::i;:::-;104400:58;;104493:9;104477:12;:25;;104469:76;;;;-1:-1:-1;;;104469:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104556:53;-1:-1:-1;;;;;104556:27:0;;104584:10;104596:12;104556:53;:27;:53;:::i;:::-;-1:-1:-1;104620:84:0;104648:10;104660:43;-1:-1:-1;;;;;104660:28:0;;104697:4;104660:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;104620:27:0;;;:84;;:27;:84;:::i;:::-;;101859:2853;;;;;;;;;;;;;:::o;100410:33::-;;;-1:-1:-1;;;;;100410:33:0;;:::o;111501:882::-;111628:7;111673:6;111697:17;-1:-1:-1;;;;;111697:15:0;;;:17::i;:::-;111692:361;;111763:37;;;-1:-1:-1;;;111763:37:0;;-1:-1:-1;;;;;111763:37:0;;;;;;;;111731:29;;45735:42;;111763:26;;:37;;;;;;;;;;;;;;;45735:42;111763:37;;;5:2:-1;;;;30:1;27;20:12;5:2;111763:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111763:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;111763:37:0;;-1:-1:-1;;;;;;111819:35:0;;;111815:227;;111875:63;-1:-1:-1;;;;;111875:26:0;;111910:12;111925;111875:63;:26;:63;:::i;:::-;111972:54;;;-1:-1:-1;;;111972:54:0;;;;;;;;112019:1;111972:54;;;;112022:3;111972:54;;;;;;-1:-1:-1;;;;;111972:32:0;;;;;:54;;;;;;;;;;;;;;-1:-1:-1;111972:32:0;:54;;;5:2:-1;;;;30:1;27;20:12;5:2;111972:54:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111972:54:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;111972:54:0;;-1:-1:-1;111815:227:0;111692:361;;112070:17;:9;-1:-1:-1;;;;;112070:15:0;;:17::i;:::-;112065:279;;112134:37;;;-1:-1:-1;;;112134:37:0;;-1:-1:-1;;;;;112134:37:0;;;;;;;;112104:27;;45735:42;;112134:26;;:37;;;;;;;;;;;;;;;45735:42;112134:37;;;5:2:-1;;;;30:1;27;20:12;5:2;112134:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112134:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;112134:37:0;;-1:-1:-1;;;;;;112190:33:0;;;112186:147;;112259:10;-1:-1:-1;;;;;112259:30:0;;112296:12;112310:1;112313:3;112259:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112259:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112259:58:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;112259:58:0;;-1:-1:-1;112186:147:0;112065:279;;112363:12;-1:-1:-1;111501:882:0;;;;;;:::o;115163:591::-;115288:7;115308:62;-1:-1:-1;;;;;115308:26:0;;45618:42;115363:6;115308:62;:26;:62;:::i;:::-;45618:42;115388:31;115426:17;-1:-1:-1;;;;;115426:15:0;;;:17::i;:::-;:30;;115455:1;115426:30;;;115446:6;115426:30;115472:17;:9;-1:-1:-1;;;;;115472:15:0;;:17::i;:::-;:43;;115506:9;115472:43;;;44035:42;115472:43;115530:6;115551:17;:9;-1:-1:-1;;;;;115551:15:0;;:17::i;:::-;:43;;115585:9;115551:43;;;44035:42;115551:43;115388:358;;;-1:-1:-1;;;;;;115388:358:0;;;;;;;-1:-1:-1;;;;;115388:358:0;;;;;;;;;;;;;;;;;;;;115617:4;115388:358;;;;-1:-1:-1;;;115388:358:0;;;;115660:1;115388:358;;;;;;115676:42;115388:358;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;115388:358:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115388:358:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115388:358:0;;115163:591;-1:-1:-1;;;;115163:591:0:o;115762:486::-;115888:7;115908:28;45876:42;-1:-1:-1;;;;;115954:32:0;;:49;;;;;;;;;;;;;-1:-1:-1;;;115954:49:0;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115954:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115954:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115954:49:0;;-1:-1:-1;116015:21:0;116039:38;116056:9;116067;116039:16;:38::i;:::-;116015:62;-1:-1:-1;116088:58:0;-1:-1:-1;;;;;116088:26:0;;116123:13;116139:6;116088:58;:26;:58;:::i;:::-;116164:13;-1:-1:-1;;;;;116164:21:0;;116192:17;:9;-1:-1:-1;;;;;116192:15:0;;:17::i;:::-;:30;;116221:1;116192:30;;;116212:6;116192:30;116224:4;116230:6;116238:1;116164:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;116164:76:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116164:76:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116164:76:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116164:76:0;;115762:486;-1:-1:-1;;;;;;115762:486:0:o;116256:722::-;116381:7;116405:17;:9;-1:-1:-1;;;;;116405:15:0;;:17::i;:::-;116401:78;;;-1:-1:-1;;;;;;;;;;;;;;;;116439:12:0;;116458:6;116439:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116439:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116439:28:0;;;;;116401:78;116491:19;116513:17;:9;-1:-1:-1;;;;;116513:15:0;;:17::i;:::-;:36;;116540:9;116513:36;;;-1:-1:-1;;;;;;;;;;;116513:36:0;116491:58;-1:-1:-1;116560:61:0;-1:-1:-1;;;;;116560:29:0;;46282:42;116614:6;116560:61;:29;:61;:::i;:::-;116632:20;46282:42;116655:27;116697:17;-1:-1:-1;;;;;116697:15:0;;;:17::i;:::-;:36;;116724:9;116697:36;;;-1:-1:-1;;;;;;;;;;;116697:36:0;116748:6;116769:17;:9;-1:-1:-1;;;;;116769:15:0;;:17::i;:::-;:36;;116796:9;116769:36;;;-1:-1:-1;;;;;;;;;;;116769:36:0;116655:177;;;-1:-1:-1;;;;;;116655:177:0;;;;;;;-1:-1:-1;;;;;116655:177:0;;;;;;;;;;;;;;;;;;;;116820:1;116655:177;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116655:177:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;116655:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116655:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116655:177:0;;-1:-1:-1;116849:17:0;-1:-1:-1;;;;;116849:15:0;;;:17::i;:::-;116845:94;;;116897:29;;;-1:-1:-1;;;116897:29:0;;116920:4;116897:29;;;;;;-1:-1:-1;;;;;;;;;;;44247:42:0;116883:13;;44247:42;;116897:14;;:29;;;;;;;;;;;;;;44247:42;116897:29;;;5:2:-1;;;;30:1;27;20:12;5:2;116897:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116897:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116897:29:0;116883:44;;;-1:-1:-1;;;;;;116883:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;116883:44:0;;;;;;;-1:-1:-1;116883:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;116883:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116883:44:0;;;;116845:94;116958:12;116256:722;-1:-1:-1;;;;;116256:722:0:o;104743:513::-;104876:7;;-1:-1:-1;;;;;104937:17:0;;-1:-1:-1;;;;;;;;;;;104937:17:0;:25;;104961:1;104937:25;;;104957:1;104937:25;-1:-1:-1;;;;;104908:16:0;;-1:-1:-1;;;;;;;;;;;104908:16:0;:24;;104931:1;104908:24;;;104927:1;104908:24;104907:56;104896:67;;;-1:-1:-1;104974:8:0;-1:-1:-1;;;;;;;;;;;;;;;;105015:17:0;;;:25;;105039:1;105015:25;;;105035:1;105015:25;-1:-1:-1;;;;;104986:16:0;;-1:-1:-1;;;;;;;;;;;104986:16:0;:24;;105009:1;104986:24;;;105005:1;104986:24;104985:56;104974:67;;;;105056:1;:6;;105061:1;105056:6;:16;;;;105066:1;:6;;105071:1;105066:6;105056:16;105052:57;;;105096:1;105089:8;;;;;;105052:57;105121:58;-1:-1:-1;;;;;105121:26:0;;46380:42;105172:6;105121:58;:26;:58;:::i;:::-;105190;;;-1:-1:-1;;;105190:58:0;;-1:-1:-1;;105224:5:0;;;105190:58;;;;;;;;;;105231:5;;;105190:58;;;;;;;;;;;;;;105246:1;105190:58;;;;;;;;46380:42;;105190:33;;:58;;;;;;;;;;;105246:1;46380:42;105190:58;;;5:2:-1;;;;30:1;27;20:12;5:2;105190:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;105190:58:0;;;;104743:513;;;;;;;:::o;105264:613::-;105393:7;;-1:-1:-1;;;;;105510:17:0;;44688:42;105510:17;:25;;105534:1;105510:25;;;105530:1;105510:25;-1:-1:-1;;;;;105467:17:0;;-1:-1:-1;;;;;;;;;;;105467:17:0;:25;;105491:1;105467:25;;;105487:1;105467:25;-1:-1:-1;;;;;105425:16:0;;-1:-1:-1;;;;;;;;;;;105425:16:0;:24;;105448:1;105425:24;;;105444:1;105425:24;105424:69;:112;105413:123;;;;105547:8;44688:42;-1:-1:-1;;;;;105644:17:0;:9;-1:-1:-1;;;;;105644:17:0;;:25;;105668:1;105644:25;;;105664:1;105644:25;-1:-1:-1;;;;;105601:17:0;;-1:-1:-1;;;;;;;;;;;105601:17:0;:25;;105625:1;105601:25;;;105621:1;105601:25;-1:-1:-1;;;;;105559:16:0;;-1:-1:-1;;;;;;;;;;;105559:16:0;:24;;105582:1;105559:24;;;105578:1;105559:24;105558:69;:112;105547:123;;;;105685:1;:6;;105690:1;105685:6;:16;;;;105695:1;:6;;105700:1;105695:6;105685:16;105681:57;;;105725:1;105718:8;;;;;;105681:57;105750:54;-1:-1:-1;;;;;105750:26:0;;46474:42;105797:6;105750:54;:26;:54;:::i;:::-;105815;;;-1:-1:-1;;;105815:54:0;;-1:-1:-1;;105845:5:0;;;105815:54;;;;;;;;;;105852:5;;;105815:54;;;;;;;;;;;;;;105867:1;105815:54;;;;;;;;46474:42;;105815:29;;:54;;;;;;;;;;;105867:1;46474:42;105815:54;;;5:2:-1;;;;30:1;27;20:12;105885:690:0;106011:7;;-1:-1:-1;;;;;106171:17:0;;44777:42;106171:17;:25;;106195:1;106171:25;;;106191:1;106171:25;-1:-1:-1;;;;;106128:17:0;;44688:42;106128:17;:25;;106152:1;106128:25;;;106148:1;106128:25;-1:-1:-1;;;;;106085:17:0;;-1:-1:-1;;;;;;;;;;;106085:17:0;:25;;106109:1;106085:25;;;106105:1;106085:25;-1:-1:-1;;;;;106043:16:0;;-1:-1:-1;;;;;;;;;;;106043:16:0;:24;;106066:1;106043:24;;;106062:1;106043:24;106042:69;:112;:155;106031:166;;;;106208:8;44777:42;-1:-1:-1;;;;;106348:17:0;:9;-1:-1:-1;;;;;106348:17:0;;:25;;106372:1;106348:25;;;106368:1;106348:25;-1:-1:-1;;;;;106305:17:0;;44688:42;106305:17;:25;;106329:1;106305:25;;;106325:1;106305:25;-1:-1:-1;;;;;106262:17:0;;-1:-1:-1;;;;;;;;;;;106262:17:0;:25;;106286:1;106262:25;;;106282:1;106262:25;-1:-1:-1;;;;;106220:16:0;;-1:-1:-1;;;;;;;;;;;106220:16:0;:24;;106243:1;106220:24;;;106239:1;106220:24;106219:69;:112;:155;106208:166;;;;106389:1;:6;;106394:1;106389:6;:16;;;;106399:1;:6;;106404:1;106399:6;106389:16;106385:57;;;106429:1;106422:8;;;;;;106385:57;106454:51;-1:-1:-1;;;;;106454:26:0;;46565:42;106498:6;106454:51;:26;:51;:::i;:::-;106516;;;-1:-1:-1;;;106516:51:0;;-1:-1:-1;;106543:5:0;;;106516:51;;;;;;;;;;106550:5;;;106516:51;;;;;;;;;;;;;;106565:1;106516:51;;;;;;;;46565:42;;106516:26;;:51;;;;;;;;;;;106565:1;46565:42;106516:51;;;5:2:-1;;;;30:1;27;20:12;106583:708:0;106715:7;;-1:-1:-1;;;;;106875:17:0;;44866:42;106875:17;:25;;106899:1;106875:25;;;106895:1;106875:25;-1:-1:-1;;;;;106832:17:0;;44688:42;106832:17;:25;;106856:1;106832:25;;;106852:1;106832:25;-1:-1:-1;;;;;106789:17:0;;-1:-1:-1;;;;;;;;;;;106789:17:0;:25;;106813:1;106789:25;;;106809:1;106789:25;-1:-1:-1;;;;;106747:16:0;;-1:-1:-1;;;;;;;;;;;106747:16:0;:24;;106770:1;106747:24;;;106766:1;106747:24;106746:69;:112;:155;106735:166;;;;106912:8;44866:42;-1:-1:-1;;;;;107052:17:0;:9;-1:-1:-1;;;;;107052:17:0;;:25;;107076:1;107052:25;;;107072:1;107052:25;-1:-1:-1;;;;;107009:17:0;;44688:42;107009:17;:25;;107033:1;107009:25;;;107029:1;107009:25;-1:-1:-1;;;;;106966:17:0;;-1:-1:-1;;;;;;;;;;;106966:17:0;:25;;106990:1;106966:25;;;106986:1;106966:25;-1:-1:-1;;;;;106924:16:0;;-1:-1:-1;;;;;;;;;;;106924:16:0;:24;;106947:1;106924:24;;;106943:1;106924:24;106923:69;:112;:155;106912:166;;;;107093:1;:6;;107098:1;107093:6;:16;;;;107103:1;:6;;107108:1;107103:6;107093:16;107089:57;;;107133:1;107126:8;;;;;;107089:57;107158;-1:-1:-1;;;;;107158:26:0;;46662:42;107208:6;107158:57;:26;:57;:::i;:::-;107226;;;-1:-1:-1;;;107226:57:0;;-1:-1:-1;;107259:5:0;;;107226:57;;;;;;;;;;107266:5;;;107226:57;;;;;;;;;;;;;;107281:1;107226:57;;;;;;;;46662:42;;107226:32;;:57;;;;;;;;;;;107281:1;46662:42;107226:57;;;5:2:-1;;;;30:1;27;20:12;107299:714:0;107433:7;;-1:-1:-1;;;;;107593:17:0;;44955:42;107593:17;:25;;107617:1;107593:25;;;107613:1;107593:25;-1:-1:-1;;;;;107550:17:0;;44688:42;107550:17;:25;;107574:1;107550:25;;;107570:1;107550:25;-1:-1:-1;;;;;107507:17:0;;-1:-1:-1;;;;;;;;;;;107507:17:0;:25;;107531:1;107507:25;;;107527:1;107507:25;-1:-1:-1;;;;;107465:16:0;;-1:-1:-1;;;;;;;;;;;107465:16:0;:24;;107488:1;107465:24;;;107484:1;107465:24;107464:69;:112;:155;107453:166;;;;107630:8;44955:42;-1:-1:-1;;;;;107770:17:0;:9;-1:-1:-1;;;;;107770:17:0;;:25;;107794:1;107770:25;;;107790:1;107770:25;-1:-1:-1;;;;;107727:17:0;;44688:42;107727:17;:25;;107751:1;107727:25;;;107747:1;107727:25;-1:-1:-1;;;;;107684:17:0;;-1:-1:-1;;;;;;;;;;;107684:17:0;:25;;107708:1;107684:25;;;107704:1;107684:25;-1:-1:-1;;;;;107642:16:0;;-1:-1:-1;;;;;;;;;;;107642:16:0;:24;;107665:1;107642:24;;;107661:1;107642:24;107641:69;:112;:155;107630:166;;;;107811:1;:6;;107816:1;107811:6;:16;;;;107821:1;:6;;107826:1;107821:6;107811:16;107807:57;;;107851:1;107844:8;;;;;;107807:57;107876:59;-1:-1:-1;;;;;107876:26:0;;46761:42;107928:6;107876:59;:26;:59;:::i;:::-;107946;;;-1:-1:-1;;;107946:59:0;;-1:-1:-1;;107981:5:0;;;107946:59;;;;;;;;;;107988:5;;;107946:59;;;;;;;;;;;;;;108003:1;107946:59;;;;;;;;46761:42;;107946:34;;:59;;;;;;;;;;;108003:1;46761:42;107946:59;;;5:2:-1;;;;30:1;27;20:12;112391:854:0;112526:7;112551:17;:9;-1:-1:-1;;;;;112551:15:0;;:17::i;:::-;112546:346;;112585:27;112615:28;112633:9;112615:17;:28::i;:::-;112585:58;-1:-1:-1;112658:57:0;-1:-1:-1;;;;;112658:26:0;;112585:58;112708:6;112658:57;:26;:57;:::i;:::-;112730:12;-1:-1:-1;;;;;112730:17:0;;112748:6;112730:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;112730:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112730:25:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;112777:103:0;;-1:-1:-1;112799:12:0;112814:9;112825:54;-1:-1:-1;;;;;112825:39:0;;112873:4;112825:54;:39;:54;:::i;:::-;112777:14;:103::i;:::-;112770:110;;;;;112546:346;112909:17;:9;-1:-1:-1;;;;;112909:15:0;;:17::i;:::-;112904:313;;112943:25;112971:28;112989:9;112971:17;:28::i;:::-;112943:56;;113014:22;113039:53;113054:9;113072:10;113085:6;113039:14;:53::i;:::-;113014:78;;113107:10;-1:-1:-1;;;;;113107:17:0;;113125:14;113107:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;113107:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;113107:33:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;113162:43:0;;-1:-1:-1;;;;;;113162:28:0;;113199:4;113162:43;:28;:43;:::i;:::-;113155:50;;;;;;112904:313;-1:-1:-1;113236:1:0;112391:854;;;;;:::o;113253:678::-;113384:7;-1:-1:-1;;;;;113408:16:0;;-1:-1:-1;;;;;;;;;;;113408:16:0;113404:254;;;113441:49;-1:-1:-1;;;;;113441:26:0;;44334:42;113483:6;113441:49;:26;:49;:::i;:::-;113505:32;;;-1:-1:-1;;;113505:32:0;;113523:4;113505:32;;;;;;;;;;;;44334:42;;113505:9;;:32;;;;;-1:-1:-1;;113505:32:0;;;;;;;-1:-1:-1;44334:42:0;113505:32;;;5:2:-1;;;;30:1;27;20:12;5:2;113505:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;113559:87:0;;-1:-1:-1;44334:42:0;;-1:-1:-1;113588:9:0;;-1:-1:-1;113599:46:0;44334:42;113639:4;113599:46;:31;:46;:::i;113559:87::-;113552:94;;;;113404:254;-1:-1:-1;;;;;113674:16:0;;-1:-1:-1;;;;;;;;;;;113674:16:0;113670:233;;;113707:18;113728:47;113743:9;44334:42;113768:6;113728:14;:47::i;:::-;113790:36;;;-1:-1:-1;;;113790:36:0;;113808:4;113790:36;;;;;;;;;;;;113707:68;;-1:-1:-1;44334:42:0;;113790:9;;:36;;;;;-1:-1:-1;;113790:36:0;;;;;;;;-1:-1:-1;44334:42:0;113790:36;;;5:2:-1;;;;30:1;27;20:12;5:2;113790:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;113848:43:0;;-1:-1:-1;;;;;;;;113848:28:0;;113885:4;113848:28;:43::i;113939:771::-;114070:7;114095:17;:9;-1:-1:-1;;;;;114095:15:0;;:17::i;:::-;114090:328;;114129:19;114151:24;114165:9;114151:13;:24::i;:::-;114129:46;;114190:47;47337:42;-1:-1:-1;;;;;114217:9:0;;:11;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114217:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114217:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114217:11:0;-1:-1:-1;;;;;114190:26:0;;;114230:6;114190:47;:26;:47;:::i;:::-;114252:37;;;-1:-1:-1;;;114252:37:0;;-1:-1:-1;;;;;114252:37:0;;;;;;;;;;;;114284:4;114252:37;;;;;;47337:42;;114252:12;;:37;;;;;-1:-1:-1;;114252:37:0;;;;;;;-1:-1:-1;47337:42:0;114252:37;;;5:2:-1;;;;30:1;27;20:12;5:2;114252:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114252:37:0;;;;114311:95;114333:8;114344:9;114355:50;114399:4;114362:8;-1:-1:-1;;;;;114355:35:0;;;:50;;;;:::i;114090:328::-;114435:17;:9;-1:-1:-1;;;;;114435:15:0;;:17::i;:::-;114430:252;;114469:17;114489:24;114503:9;114489:13;:24::i;:::-;114469:44;;114528:18;114549:49;114564:9;114582:6;114591;114549:14;:49::i;:::-;114528:70;;114613:6;-1:-1:-1;;;;;114613:13:0;;114627:10;114613:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114613:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114613:25:0;;;;114660:10;114653:17;;;;;;114718:437;114847:7;114867:20;47667:42;-1:-1:-1;;;;;114890:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114890:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114890:26:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114890:26:0;;-1:-1:-1;114927:54:0;-1:-1:-1;;;;;114927:26:0;;114890;114974:6;114927:54;:26;:54;:::i;:::-;114999:9;-1:-1:-1;;;;;114999:14:0;;115020:17;:9;-1:-1:-1;;;;;115020:15:0;;:17::i;:::-;:30;;115049:1;115020:30;;;115040:6;115020:30;114999:148;;;-1:-1:-1;;;;;;114999:148:0;;;;;;;-1:-1:-1;;;;;114999:148:0;;;;;;;;;;;;;;;;;;;115135:1;114999:148;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;114999:148:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114999:148:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114999:148:0;;114718:437;-1:-1:-1;;;;;114718:437:0:o;118390:268::-;118519:7;118546:104;118585:9;118609;118633:6;118546:24;:104::i;118666:289::-;118798:7;118825:122;118863:9;-1:-1:-1;;;;;;;;;;;118906:9:0;118930:6;118825:23;:122::i;118963:288::-;119095:7;119122:121;119160:9;-1:-1:-1;;;;;;;;;;;119202:9:0;119226:6;119122:23;:121::i;119259:290::-;119392:7;119419:122;119457:9;-1:-1:-1;;;;;;;;;;;119500:9:0;119524:6;119419:23;:122::i;108021:694::-;108149:7;;-1:-1:-1;;;;;108309:16:0;;45043:42;108309:16;:24;;108332:1;108309:24;;;108328:1;108309:24;-1:-1:-1;;;;;108266:17:0;;44688:42;108266:17;:25;;108290:1;108266:25;;;108286:1;108266:25;-1:-1:-1;;;;;108223:17:0;;-1:-1:-1;;;;;;;;;;;108223:17:0;:25;;108247:1;108223:25;;;108243:1;108223:25;-1:-1:-1;;;;;108181:16:0;;-1:-1:-1;;;;;;;;;;;108181:16:0;:24;;108204:1;108181:24;;;108200:1;108181:24;108180:69;:112;:154;108169:165;;;;108345:8;45043:42;-1:-1:-1;;;;;108485:16:0;:9;-1:-1:-1;;;;;108485:16:0;;:24;;108508:1;108485:24;;;108504:1;108485:24;-1:-1:-1;;;;;108442:17:0;;44688:42;108442:17;:25;;108466:1;108442:25;;;108462:1;108442:25;-1:-1:-1;;;;;108399:17:0;;-1:-1:-1;;;;;;;;;;;108399:17:0;:25;;108423:1;108399:25;;;108419:1;108399:25;-1:-1:-1;;;;;108357:16:0;;-1:-1:-1;;;;;;;;;;;108357:16:0;:24;;108380:1;108357:24;;;108376:1;108357:24;108356:69;:112;:154;108345:165;;;;108525:1;:6;;108530:1;108525:6;:16;;;;108535:1;:6;;108540:1;108535:6;108525:16;108521:57;;;108565:1;108558:8;;;;;;108521:57;108590:53;-1:-1:-1;;;;;108590:26:0;;46854:42;108636:6;108590:53;:26;:53;:::i;:::-;108654;;;-1:-1:-1;;;108654:53:0;;-1:-1:-1;;108683:5:0;;;108654:53;;;;;;;;;;108690:5;;;108654:53;;;;;;;;;;;;;;108705:1;108654:53;;;;;;;;46854:42;;108654:28;;:53;;;;;;;;;;;108705:1;46854:42;108654:53;;;5:2:-1;;;;30:1;27;20:12;109460:528:0;109591:7;;-1:-1:-1;;;;;109668:17:0;;45223:42;109668:17;:25;;109692:1;109668:25;;;109688:1;109668:25;-1:-1:-1;;;;;109623:19:0;;45134:42;109623:19;:27;;109649:1;109623:27;;;109645:1;109623:27;109622:72;109611:83;;;-1:-1:-1;109705:8:0;45223:42;-1:-1:-1;;;;;109762:17:0;;;:25;;109786:1;109762:25;;;109782:1;109762:25;-1:-1:-1;;;;;109717:19:0;;45134:42;109717:19;:27;;109743:1;109717:27;;;109739:1;109717:27;109716:72;109705:83;;;;109803:1;:6;;109808:1;109803:6;:16;;;;109813:1;:6;;109818:1;109813:6;109803:16;109799:57;;;109843:1;109836:8;;;;;;109799:57;109868:56;-1:-1:-1;;;;;109868:26:0;;46950:42;109917:6;109868:56;:26;:56;:::i;:::-;109935:45;;;-1:-1:-1;;;109935:45:0;;-1:-1:-1;;109956:5:0;;;109935:45;;;;;;;;;;109963:5;;;109935:45;;;;;;;;;;;;;;109978:1;109935:45;;;;;;;;46950:42;;109935:20;;:45;;;;;;;;;;;109978:1;46950:42;109935:45;;;5:2:-1;;;;30:1;27;20:12;109996:604:0;110125:7;;-1:-1:-1;;;;;110243:17:0;;45401:42;110243:17;:25;;110267:1;110243:25;;;110263:1;110243:25;-1:-1:-1;;;;;110200:17:0;;45223:42;110200:17;:25;;110224:1;110200:25;;;110220:1;110200:25;-1:-1:-1;;;;;110157:17:0;;45312:42;110157:17;:25;;110181:1;110157:25;;;110177:1;110157:25;110156:70;:113;110145:124;;;;110280:8;45401:42;-1:-1:-1;;;;;110378:17:0;:9;-1:-1:-1;;;;;110378:17:0;;:25;;110402:1;110378:25;;;110398:1;110378:25;-1:-1:-1;;;;;110335:17:0;;45223:42;110335:17;:25;;110359:1;110335:25;;;110355:1;110335:25;-1:-1:-1;;;;;110292:17:0;;45312:42;110292:17;:25;;110316:1;110292:25;;;110312:1;110292:25;110291:70;:113;110280:124;;;;110419:1;:6;;110424:1;110419:6;:16;;;;110429:1;:6;;110434:1;110429:6;110419:16;110415:57;;;110459:1;110452:8;;;;;;110415:57;110484:54;-1:-1:-1;;;;;110484:26:0;;47044:42;110531:6;110484:54;:26;:54;:::i;:::-;110549:43;;;-1:-1:-1;;;110549:43:0;;-1:-1:-1;;110568:5:0;;;110549:43;;;;;;;;;;110575:5;;;110549:43;;;;;;;;;;;;;;110590:1;110549:43;;;;;;;;47044:42;;110549:18;;:43;;;;;;;;;;;110590:1;47044:42;110549:43;;;5:2:-1;;;;30:1;27;20:12;111224:269:0;111354:7;111374:55;-1:-1:-1;;;;;111374:26:0;;47888:42;111422:6;111374:55;:26;:55;:::i;:::-;111440:45;;;-1:-1:-1;;;111440:45:0;;-1:-1:-1;;;;;111440:45:0;;;;;;;;;;;;;;;;;;;;;47888:42;;111440:15;;:45;;;;;-1:-1:-1;;111440:45:0;;;;;;;-1:-1:-1;47888:42:0;111440:45;;;5:2:-1;;;;30:1;27;20:12;5:2;111440:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;111440:45:0;;;;111224:269;;;;;:::o;108723:377::-;108849:7;108869:50;-1:-1:-1;;;;;108869:26:0;;47228:42;108912:6;108869:50;:26;:50;:::i;:::-;108937:155;;;-1:-1:-1;;;108937:155:0;;-1:-1:-1;;;;;108937:155:0;;;;;;;;;;;;;;;;;;;109057:1;108937:155;;;;;;109079:2;109073:3;:8;108937:155;;;;;;47228:42;;108937:18;;:155;;;;;;;;;;;;;;;;;;47228:42;108937:155;;;5:2:-1;;;;30:1;27;20:12;5:2;108937:155:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108937:155:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;109108:344:0;109240:7;109260:49;-1:-1:-1;;;;;109260:26:0;;47981:42;109302:6;109260:49;:26;:49;:::i;:::-;109327:117;;;-1:-1:-1;;;109327:117:0;;-1:-1:-1;;;;;109327:117:0;;;;;;;;;;;;;;;;;;;109428:4;109327:117;;;;;;47981:42;;109327:9;;:117;;;;;;;;;;;;;;-1:-1:-1;47981:42:0;109327:117;;;5:2:-1;;;;30:1;27;20:12;110608:608:0;110737:7;;-1:-1:-1;;;;;110857:17:0;;45490:42;110857:17;:25;;110881:1;110857:25;;;110877:1;110857:25;-1:-1:-1;;;;;110814:17:0;;45223:42;110814:17;:25;;110838:1;110814:25;;;110834:1;110814:25;-1:-1:-1;;;;;110769:19:0;;45134:42;110769:19;:27;;110795:1;110769:27;;;110791:1;110769:27;110768:72;:115;110757:126;;;;110894:8;45490:42;-1:-1:-1;;;;;110994:17:0;:9;-1:-1:-1;;;;;110994:17:0;;:25;;111018:1;110994:25;;;111014:1;110994:25;-1:-1:-1;;;;;110951:17:0;;45223:42;110951:17;:25;;110975:1;110951:25;;;110971:1;110951:25;-1:-1:-1;;;;;110906:19:0;;45134:42;110906:19;:27;;110932:1;110906:27;;;110928:1;110906:27;110905:72;:115;110894:126;;;;111035:1;:6;;111040:1;111035:6;:16;;;;111045:1;:6;;111050:1;111045:6;111035:16;111031:57;;;111075:1;111068:8;;;;;;111031:57;111100:54;-1:-1:-1;;;;;111100:26:0;;47138:42;111147:6;111100:54;:26;:54;:::i;:::-;111165:43;;;-1:-1:-1;;;111165:43:0;;-1:-1:-1;;111184:5:0;;;111165:43;;;;;;;;;;111191:5;;;111165:43;;;;;;;;;;;;;;111206:1;111165:43;;;;;;;;47138:42;;111165:18;;:43;;;;;;;;;;;111206:1;47138:42;111165:43;;;5:2:-1;;;;30:1;27;20:12;120498:206:0;120627:7;120647:49;120664:9;120675;120686:6;120694:1;120647:16;:49::i;:::-;;120498:206;;;;;:::o;120712:::-;120841:7;120861:49;120878:9;120889;120900:6;120908:1;120861:16;:49::i;120926:206::-;121055:7;121075:49;121092:9;121103;121114:6;121122:1;121075:16;:49::i;10552:181::-;10610:7;10642:5;;;10666:6;;;;10658:46;;;;;-1:-1:-1;;;10658:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;10724:1;-1:-1:-1;10552:181:0;;;;;:::o;36488:166::-;36539:4;-1:-1:-1;;;;;36564:39:0;;;;:81;;-1:-1:-1;;;;;;36607:38:0;;33660:42;36607:38;36564:81;36556:90;;36488:166;;;;:::o;34068:617::-;34179:11;34175:50;;34207:7;;34175:50;34241:12;34247:5;34241;:12::i;:::-;34237:441;;;-1:-1:-1;;;;;34278:18:0;;34286:10;34278:18;:41;;;;;34313:6;34300:9;:19;;34278:41;34270:97;;;;-1:-1:-1;;;34270:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;34386:19:0;;34400:4;34386:19;34382:97;;34426:37;;-1:-1:-1;;;;;34426:29:0;;;:37;;;;;34456:6;;34426:37;;;;34456:6;34426:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;34426:37:0;34382:97;34509:6;34497:9;:18;34493:101;;;34536:10;:42;34556:21;:9;34570:6;34556:21;:13;:21;:::i;:::-;34536:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;34536:42:0;34493:101;34237:441;;;34626:40;-1:-1:-1;;;;;34626:22:0;;34649:4;34655:2;34659:6;34626:40;:22;:40;:::i;:::-;34068:617;;;;:::o;35670:228::-;35748:7;35772:12;35778:5;35772;:12::i;:::-;35768:123;;;-1:-1:-1;;;;;;35808:11:0;;;35801:18;;35768:123;35859:5;-1:-1:-1;;;;;35859:15:0;;35875:3;35859:20;;;;;;;;;;;;;-1:-1:-1;;;;;35859:20:0;-1:-1:-1;;;;;35859:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35859:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;35859:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;35859:20:0;;-1:-1:-1;35852:27:0;;11924:471;11982:7;12227:6;12223:47;;-1:-1:-1;12257:1:0;12250:8;;12223:47;12294:5;;;12298:1;12294;:5;:1;12318:5;;;;;:10;12310:56;;;;-1:-1:-1;;;12310:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12863:132;12921:7;12948:39;12952:1;12955;12948:39;;;;;;;;;;;;;;;;;:3;:39::i;33712:348::-;33798:4;33819:11;33815:55;;-1:-1:-1;33854:4:0;33847:11;;33815:55;33886:12;33892:5;33886;:12::i;:::-;33882:171;;;33915:37;;-1:-1:-1;;;;;33915:29:0;;;:37;;;;;33945:6;;33915:37;;;;33945:6;33915:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;33915:37:0;33882:171;;;33985:30;-1:-1:-1;;;;;33985:18:0;;34004:2;34008:6;33985:30;:18;:30;:::i;:::-;-1:-1:-1;34037:4:0;34030:11;;35144:518;35237:12;35243:5;35237;:12::i;:::-;35232:423;;35270:11;35266:101;;35302:24;-1:-1:-1;;;;;35302:17:0;;35320:2;35324:1;35302:24;:17;:24;:::i;:::-;35345:7;;35266:101;35403:34;;;-1:-1:-1;;;35403:34:0;;35427:4;35403:34;;;;-1:-1:-1;;;;;35403:34:0;;;;;;;;;35383:17;;35403:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;35403:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;35403:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;35403:34:0;;-1:-1:-1;35456:18:0;;;35452:192;;;35499:13;;35495:86;;35537:24;-1:-1:-1;;;;;35537:17:0;;35555:2;35559:1;35537:24;:17;:24;:::i;:::-;35599:29;-1:-1:-1;;;;;35599:17:0;;35617:2;35621:6;35599:29;:17;:29;:::i;35232:423::-;35144:518;;;:::o;50104:2554::-;50213:21;50264:9;-1:-1:-1;;;;;50251:22:0;:9;-1:-1:-1;;;;;50251:22:0;;50247:78;;;-1:-1:-1;50297:16:0;;;50311:1;50297:16;;;;;;;;50290:23;;50247:78;50341:17;:9;-1:-1:-1;;;;;50341:15:0;;:17::i;:::-;50337:73;;;44035:42;50375:23;;50337:73;50424:17;:9;-1:-1:-1;;;;;50424:15:0;;:17::i;:::-;50420:73;;;44035:42;50458:23;;50420:73;-1:-1:-1;;;;;50509:16:0;;44510:42;50509:16;;:36;;-1:-1:-1;;;;;;50529:16:0;;44510:42;50529:16;50509:36;50505:148;;;50569:16;;;50583:1;50569:16;;;;;;;;;;;;;17:15:-1;;105:10;50569:16:0;88:34:-1;136:17;;-1:-1;50569:16:0;50562:23;;50505:148;;;50625:16;;;50639:1;50625:16;;;;;;;;;;;;;17:15:-1;;105:10;50625:16:0;88:34:-1;136:17;;-1:-1;50625:16:0;50618:23;;50505:148;50665:21;50697:19;50729:48;45876:42;-1:-1:-1;;;;;50805:32:0;;:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50805:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;50805:59:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50805:59:0;;-1:-1:-1;;;;;;50882:16:0;;44510:42;50882:16;50878:593;;50916:12;50930:17;-1:-1:-1;;;;;50951:43:0;;;;50999:6;;-1:-1:-1;;;51048:62:0;51129:17;;:15;;;:17::i;:::-;:43;;51163:9;51129:43;;;44035:42;51129:43;51007:200;;;-1:-1:-1;;;;;51007:200:0;;;;;;;51191:1;51007:200;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;51007:200:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;51007:200:0;;;179:29:-1;;;;160:49;;50951:257:0;;;51007:200;;50951:257;;;;25:18:-1;50951:257:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;50951:257:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;50915:293:0;;;;51228:7;51223:72;;51263:16;;;51277:1;51263:16;;;;;;;;;;;;51256:23;;;;;;;;;51223:72;51338:4;51327:27;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;51327:27:0;;-1:-1:-1;;;;;;51373:27:0;;51369:91;;51428:16;;;51442:1;51428:16;;;;;;;;;;;;51369:91;50878:593;;;-1:-1:-1;;;;;51487:16:0;;44510:42;51487:16;51483:589;;51521:12;51535:17;-1:-1:-1;;;;;51556:43:0;;;;51604:6;;-1:-1:-1;;;51653:62:0;51734:17;;:15;;;:17::i;:::-;:43;;51768:9;51734:43;;;44035:42;51734:43;51612:200;;;-1:-1:-1;;;;;51612:200:0;;;;;;;51796:1;51612:200;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;51612:200:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;51612:200:0;;;179:29:-1;;;;160:49;;51556:257:0;;;51612:200;;51556:257;;;;25:18:-1;51556:257:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;51556:257:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;51520:293:0;;;;51833:7;51828:72;;51868:16;;;51882:1;51868:16;;;;;;;;;;;;51828:72;51941:4;51930:27;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;51930:27:0;;-1:-1:-1;;;;;;51976:25:0;;51972:89;;52029:16;;;52043:1;52029:16;;;;;;;;;;;;51972:89;51483:589;;;-1:-1:-1;;;;;52088:16:0;;44510:42;52088:16;52084:178;;;52139:9;52121:4;52126:1;52121:7;;;;;;;;;;;;;:28;-1:-1:-1;;;;;52121:28:0;;;-1:-1:-1;;;;;52121:28:0;;;;;52174:13;52164:4;52169:1;52164:7;;;;;;;;;;;;;:23;-1:-1:-1;;;;;52164:23:0;;;-1:-1:-1;;;;;52164:23:0;;;;;44510:42;52202:4;52207:1;52202:7;;;;;;;;-1:-1:-1;;;;;52202:22:0;;;:7;;;;;;;;;;;:22;-1:-1:-1;52239:11:0;;-1:-1:-1;;52239:11:0;52084:178;-1:-1:-1;;;;;52278:16:0;;44510:42;52278:16;52274:176;;;44510:42;52311:4;52316:1;52311:7;;;;;;;;;;;;;:22;-1:-1:-1;;;;;52311:22:0;;;-1:-1:-1;;;;;52311:22:0;;;;;52358:11;52348:4;52353:1;52348:7;;;;;;;;;;;;;:21;-1:-1:-1;;;;;52348:21:0;;;-1:-1:-1;;;;;52348:21:0;;;;;52402:9;52384:4;52389:1;52384:7;;;;;;;52274:176;52480:9;52462:4;52467:1;52462:7;;;;;;;;;;;;;:28;-1:-1:-1;;;;;52462:28:0;;;-1:-1:-1;;;;;52462:28:0;;;;;52511:13;52501:4;52506:1;52501:7;;;;;;;;;;;;;:23;-1:-1:-1;;;;;52501:23:0;;;-1:-1:-1;;;;;52501:23:0;;;;;44510:42;52535:4;52540:1;52535:7;;;;;;;;;;;;;:22;-1:-1:-1;;;;;52535:22:0;;;-1:-1:-1;;;;;52535:22:0;;;;;52578:11;52568:4;52573:1;52568:7;;;;;;;;;;;;;:21;-1:-1:-1;;;;;52568:21:0;;;-1:-1:-1;;;;;52568:21:0;;;;;52618:9;52600:4;52605:1;52600:7;;;;;;;;-1:-1:-1;;;;;52600:28:0;;;:7;;;;;;;;;;;:28;-1:-1:-1;;;50104:2554:0;;;;:::o;52666:1473::-;52729:14;52760:13;:5;-1:-1:-1;;;;;52760:11:0;;:13::i;:::-;52756:118;;;-1:-1:-1;52819:42:0;52797:65;;52756:118;-1:-1:-1;;;;;52888:59:0;;-1:-1:-1;;;;;;;;;;;52888:59:0;52884:164;;;-1:-1:-1;52993:42:0;52971:65;;52884:164;-1:-1:-1;;;;;53062:59:0;;53078:42;53062:59;53058:164;;;-1:-1:-1;53167:42:0;53145:65;;53058:164;-1:-1:-1;;;;;53236:59:0;;53252:42;53236:59;53232:164;;;-1:-1:-1;53341:42:0;53319:65;;53232:164;-1:-1:-1;;;;;53410:59:0;;-1:-1:-1;;;;;;;;;;;53410:59:0;53406:165;;;-1:-1:-1;53516:42:0;53494:65;;53406:165;-1:-1:-1;;;;;53585:59:0;;53601:42;53585:59;53581:165;;;-1:-1:-1;53691:42:0;53669:65;;53581:165;-1:-1:-1;;;;;53760:59:0;;53776:42;53760:59;53756:164;;;-1:-1:-1;53865:42:0;53843:65;;53756:164;-1:-1:-1;;;;;53934:59:0;;53950:42;53934:59;53930:165;;;-1:-1:-1;54040:42:0;54018:65;;53930:165;-1:-1:-1;54129:1:0;52666:1473;;;:::o;54147:2965::-;54206:10;54233:13;:5;-1:-1:-1;;;;;54233:11:0;;:13::i;:::-;54229:114;;;-1:-1:-1;54288:42:0;54270:61;;54229:114;-1:-1:-1;;;;;54357:59:0;;-1:-1:-1;;;;;;;;;;;54357:59:0;54353:160;;;-1:-1:-1;54458:42:0;54440:61;;54353:160;-1:-1:-1;;;;;54527:59:0;;-1:-1:-1;;;;;;;;;;;54527:59:0;54523:161;;;-1:-1:-1;54629:42:0;54611:61;;54523:161;-1:-1:-1;;;;;54698:59:0;;54714:42;54698:59;54694:161;;;-1:-1:-1;54800:42:0;54782:61;;54694:161;-1:-1:-1;;;;;54869:59:0;;54885:42;54869:59;54865:161;;;-1:-1:-1;54971:42:0;54953:61;;54865:161;-1:-1:-1;;;;;55040:59:0;;55056:42;55040:59;55036:161;;;-1:-1:-1;55142:42:0;55124:61;;55036:161;-1:-1:-1;;;;;55211:59:0;;55227:42;55211:59;55207:161;;;-1:-1:-1;55313:42:0;55295:61;;55207:161;-1:-1:-1;;;;;55382:59:0;;55398:42;55382:59;55378:160;;;-1:-1:-1;55483:42:0;55465:61;;55378:160;-1:-1:-1;;;;;55552:59:0;;55568:42;55552:59;55548:160;;;-1:-1:-1;55653:42:0;55635:61;;55548:160;-1:-1:-1;;;;;55722:59:0;;55738:42;55722:59;55718:161;;;-1:-1:-1;55824:42:0;55806:61;;55718:161;-1:-1:-1;;;;;55893:59:0;;55909:42;55893:59;55889:161;;;-1:-1:-1;55995:42:0;55977:61;;55889:161;-1:-1:-1;;;;;56064:59:0;;56080:42;56064:59;56060:161;;;-1:-1:-1;56166:42:0;56148:61;;56060:161;-1:-1:-1;;;;;56235:59:0;;56251:42;56235:59;56231:160;;;-1:-1:-1;56336:42:0;56318:61;;56231:160;-1:-1:-1;;;;;56405:59:0;;56421:42;56405:59;56401:160;;;-1:-1:-1;56506:42:0;56488:61;;56401:160;-1:-1:-1;;;;;56575:59:0;;56591:42;56575:59;56571:160;;;-1:-1:-1;56676:42:0;56658:61;;56571:160;-1:-1:-1;;;;;56745:59:0;;56761:42;56745:59;56741:161;;;-1:-1:-1;56847:42:0;56829:61;;56741:161;-1:-1:-1;;;;;56916:59:0;;56932:42;56916:59;56912:160;;;-1:-1:-1;57017:42:0;56999:61;;116986:975;117123:20;117160:17;:9;-1:-1:-1;;;;;117160:15:0;;:17::i;:::-;117156:78;;;-1:-1:-1;;;;;;;;;;;;;;;;117194:12:0;;117213:6;117194:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;117194:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117194:28:0;;;;;117156:78;117246:20;117269:17;:9;-1:-1:-1;;;;;117269:15:0;;:17::i;:::-;:36;;117296:9;117269:36;;;-1:-1:-1;;;;;;;;;;;117269:36:0;117246:59;;117316:18;117337:17;:9;-1:-1:-1;;;;;117337:15:0;;:17::i;:::-;:36;;117364:9;117337:36;;;-1:-1:-1;;;;;;;;;;;117337:36:0;117414:45;;;-1:-1:-1;;;117414:45:0;;-1:-1:-1;;;;;117414:45:0;;;;;;;;;;;;;;;117316:57;;-1:-1:-1;117384:27:0;;47783:42;;117414:17;;:45;;;;;;;;;;;;;;47783:42;117414:45;;;5:2:-1;;;;30:1;27;20:12;5:2;117414:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117414:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117414:45:0;;-1:-1:-1;117485:54:0;-1:-1:-1;;;;;117485:18:0;;117504:13;117519:11;117532:6;117485:54;:18;:54;:::i;:::-;117470:69;-1:-1:-1;117552:58:0;-1:-1:-1;;;;;117552:31:0;;117592:8;117603:6;117552:58;:31;:58;:::i;:::-;;117675:11;-1:-1:-1;;;;;117659:29:0;117641:13;-1:-1:-1;;;;;117625:31:0;:63;117621:227;;;117705:49;;;-1:-1:-1;;;117705:49:0;;117719:1;117705:49;;;;;;;;;;;;117744:4;117705:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;117705:13:0;;;;;:49;;;;;;;;;;;117719:1;117705:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;117705:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117705:49:0;;;;117621:227;;;117787:49;;;-1:-1:-1;;;117787:49:0;;;;;;;;117815:1;117787:49;;;;;;117826:4;117787:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;117787:13:0;;;;;:49;;;;;;;;;;;117815:1;117787:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;117787:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117787:49:0;;;;117621:227;117864:17;:9;-1:-1:-1;;;;;117864:15:0;;:17::i;:::-;117860:94;;;117912:29;;;-1:-1:-1;;;117912:29:0;;117935:4;117912:29;;;;;;-1:-1:-1;;;;;;;;;;;44247:42:0;117898:13;;44247:42;;117912:14;;:29;;;;;;;;;;;;;;44247:42;117912:29;;;5:2:-1;;;;30:1;27;20:12;5:2;117912:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117912:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117912:29:0;117898:44;;;-1:-1:-1;;;;;;117898:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;117898:44:0;;;;;;;-1:-1:-1;117898:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;117898:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117898:44:0;;;;117860:94;116986:975;;;;;;;;:::o;117969:413::-;118131:7;118158:216;118197:8;118220:9;118244:119;118287:9;118315:8;118342:6;118244:24;:119::i;:::-;118158:24;:216::i;119557:933::-;119714:7;119734:22;48240:42;119759:38;119820:17;-1:-1:-1;;;;;119820:15:0;;;:17::i;:::-;:36;;119847:9;119820:36;;;-1:-1:-1;;;;;;;;;;;119820:36:0;119880:17;:9;-1:-1:-1;;;;;119880:15:0;;:17::i;:::-;:36;;119907:9;119880:36;;;-1:-1:-1;;;;;;;;;;;119880:36:0;119932:9;119944:1;119932:13;119759:197;;;;;;;;;;;;;-1:-1:-1;;;;;119759:197:0;-1:-1:-1;;;;;119759:197:0;;;;;;-1:-1:-1;;;;;119759:197:0;-1:-1:-1;;;;;119759:197:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119759:197:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119759:197:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;119759:197:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;119759:197:0;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;261:11;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;119759:197:0;;421:4:-1;412:14;;;;119759:197:0;;;;;412:14:-1;119759:197:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;119759:197:0;;;;;;;;;;;119734:222;;119973:17;:9;-1:-1:-1;;;;;119973:15:0;;:17::i;:::-;119969:78;;;-1:-1:-1;;;;;;;;;;;;;;;;120007:12:0;;120026:6;120007:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120007:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120007:28:0;;;;;119969:78;120059:81;120115:5;120121:9;120115:16;;;;;;;;;;;;;;120133:6;120060:17;:9;-1:-1:-1;;;;;120060:15:0;;:17::i;:::-;:36;;120087:9;120060:36;;;-1:-1:-1;;;;;;;;;;;120060:36:0;-1:-1:-1;;;;;120059:55:0;;:81;;:55;:81;:::i;:::-;120165:5;120171:9;120165:16;;;;;;;;;;;;;;-1:-1:-1;;;;;120151:49:0;;120215:17;:9;-1:-1:-1;;;;;120215:15:0;;:17::i;:::-;:36;;120242:9;120215:36;;;-1:-1:-1;;;;;;;;;;;120215:36:0;120266:6;120287:17;:9;-1:-1:-1;;;;;120287:15:0;;:17::i;:::-;:36;;120314:9;120287:36;;;-1:-1:-1;;;;;;;;;;;120287:36:0;120338:1;-1:-1:-1;;120151:225:0;;;;;;;;;;;;;-1:-1:-1;;;;;120151:225:0;-1:-1:-1;;;;;120151:225:0;;;;;;;;;;;-1:-1:-1;;;;;120151:225:0;-1:-1:-1;;;;;120151:225:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120151:225:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120151:225:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;120393:17:0;;-1:-1:-1;;;;;;120393:15:0;;;:17::i;:::-;120389:94;;;120441:29;;;-1:-1:-1;;;120441:29:0;;120464:4;120441:29;;;;;;-1:-1:-1;;;;;;;;;;;44247:42:0;120427:13;;44247:42;;120441:14;;:29;;;;;;;;;;;;;;44247:42;120441:29;;;5:2:-1;;;;30:1;27;20:12;5:2;120441:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120441:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;120441:29:0;120427:44;;;-1:-1:-1;;;;;;120427:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;120427:44:0;;;;;;;-1:-1:-1;120427:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;120427:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120427:44:0;;;;120389:94;119557:933;;;;;;;:::o;11008:136::-;11066:7;11093:43;11097:1;11100;11093:43;;;;;;;;;;;;;;;;;:3;:43::i;30367:204::-;30494:68;;;-1:-1:-1;;;;;30494:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;30494:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;30468:95:0;;30487:5;;30468:18;:95::i;13525:345::-;13611:7;13713:12;13706:5;13698:28;;;;-1:-1:-1;;;13698:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;13698:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13737:9;13753:1;13749;:5;;;;;;;13525:345;-1:-1:-1;;;;;13525:345:0:o;30183:176::-;30292:58;;;-1:-1:-1;;;;;30292:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;30292:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;30266:85:0;;30285:5;;30266:18;:85::i;30579:621::-;30949:10;;;30948:62;;-1:-1:-1;30965:39:0;;;-1:-1:-1;;;30965:39:0;;30989:4;30965:39;;;;-1:-1:-1;;;;;30965:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;30965:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;30965:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30965:39:0;:44;30948:62;30940:152;;;;-1:-1:-1;;;30940:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31129:62;;;-1:-1:-1;;;;;31129:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;31129:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;31103:89:0;;31122:5;;31103:18;:89::i;37120:599::-;37285:7;;37325:47;-1:-1:-1;;;;;37325:28:0;;37362:8;37325:47;:28;:47;:::i;:::-;37305:67;-1:-1:-1;37383:18:0;37404:47;-1:-1:-1;;;;;37404:28:0;;37441:8;37404:47;:28;:47;:::i;:::-;37383:68;-1:-1:-1;37464:23:0;37490:17;:8;37503:3;37490:17;:12;:17;:::i;:::-;37464:43;-1:-1:-1;37518:17:0;37538:31;37464:43;37558:10;37538:31;:19;:31;:::i;:::-;37518:51;-1:-1:-1;37580:19:0;37602:40;37626:15;37602:19;:9;37616:4;37602:19;:13;:19;:::i;:::-;:23;:40;:23;:40;:::i;:::-;37580:62;-1:-1:-1;37661:16:0;;37660:51;;37685:26;:9;37699:11;37685:26;:13;:26;:::i;:::-;37660:51;;;37681:1;37660:51;37653:58;37120:599;-1:-1:-1;;;;;;;;;;37120:599:0:o;11481:192::-;11567:7;11603:12;11595:6;;;;11587:29;;;;-1:-1:-1;;;11587:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;11587:29:0;-1:-1:-1;;;11639:5:0;;;11481:192::o;32222:1114::-;32826:27;32834:5;-1:-1:-1;;;;;32826:25:0;;:27::i;:::-;32818:71;;;;;-1:-1:-1;;;32818:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;32963:12;32977:23;33012:5;-1:-1:-1;;;;;33004:19:0;33024:4;33004:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;33004:25:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;32962:67:0;;;;33048:7;33040:52;;;;;-1:-1:-1;;;33040:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33109:17;;:21;33105:224;;33251:10;33240:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;33240:30:0;33232:85;;;;-1:-1:-1;;;33232:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27212:619;27272:4;27740:20;;27583:66;27780:23;;;;;;:42;;-1:-1:-1;27807:15:0;;;27780:42;27772:51;27212:619;-1:-1:-1;;;;27212:619:0:o;100358:20777::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;
Swarm Source
bzzr://11f96d9b4dc5bb090d921b8c3f4ea696379369f1bd7e9a75b0a1c639a86cc00a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BSC | 100.00% | $7.5 | 1 | $7.5 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.