Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Swap | 16079525 | 826 days ago | IN | 0 ETH | 0.00224557 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
16079525 | 826 days ago | 1 wei | ||||
16079525 | 826 days ago | 1 wei | ||||
11265221 | 1570 days ago | 0.15594629 ETH | ||||
11265221 | 1570 days ago | 0.15594629 ETH | ||||
11159436 | 1586 days ago | 20.35861504 ETH | ||||
11159436 | 1586 days ago | 20.35861504 ETH | ||||
11125644 | 1592 days ago | 0.19158917 ETH | ||||
11125644 | 1592 days ago | 0.19158906 ETH | ||||
11091140 | 1597 days ago | 2.5063056 ETH | ||||
11091140 | 1597 days ago | 2.50630571 ETH | ||||
11081406 | 1598 days ago | 0.21708772 ETH | ||||
11081406 | 1598 days ago | 0.21708772 ETH | ||||
11080962 | 1598 days ago | 6.03718891 ETH | ||||
11080962 | 1598 days ago | 3.02070964 ETH | ||||
11080962 | 1598 days ago | 3.01647927 ETH | ||||
11077747 | 1599 days ago | 1.47806057 ETH | ||||
11077747 | 1599 days ago | 0.73790739 ETH | ||||
11077747 | 1599 days ago | 0.74015318 ETH | ||||
11068652 | 1600 days ago | 69.2177169 ETH | ||||
11068652 | 1600 days ago | 34.09767085 ETH | ||||
11068652 | 1600 days ago | 35.12004604 ETH | ||||
11068261 | 1600 days ago | 1.9391901 ETH | ||||
11068261 | 1600 days ago | 0.96795599 ETH | ||||
11068261 | 1600 days ago | 0.9712341 ETH | ||||
11036565 | 1605 days ago | 6.29264661 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
OneSplitWrap
Compiler Version
v0.5.12+commit.7709ece9
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-05-20 */ // 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; // // || // || // \/ // +--------------+ // | OneSplitWrap | // +--------------+ // || // || (delegatecall) // \/ // +--------------+ // | OneSplit | // +--------------+ // // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_KYBER + ... uint256 public constant FLAG_DISABLE_UNISWAP = 0x01; uint256 public constant FLAG_DISABLE_KYBER = 0x02; uint256 public constant FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x100000000; // Turned off by default uint256 public constant FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x200000000; // Turned off by default uint256 public constant FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x400000000; // Turned off by default uint256 public constant FLAG_DISABLE_BANCOR = 0x04; uint256 public constant FLAG_DISABLE_OASIS = 0x08; uint256 public constant FLAG_DISABLE_COMPOUND = 0x10; uint256 public constant FLAG_DISABLE_FULCRUM = 0x20; uint256 public constant FLAG_DISABLE_CHAI = 0x40; uint256 public constant FLAG_DISABLE_AAVE = 0x80; uint256 public constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 public constant FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Turned off by default uint256 public constant FLAG_DISABLE_BDAI = 0x400; uint256 public constant FLAG_DISABLE_IEARN = 0x800; uint256 public constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 public constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 public constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 public constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 public constant FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Turned off by default uint256 public constant FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Turned off by default uint256 public constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 public constant FLAG_DISABLE_WETH = 0x80000; uint256 public constant FLAG_ENABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 public constant FLAG_ENABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 public constant FLAG_ENABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 public constant FLAG_DISABLE_IDLE = 0x800000; uint256 public constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x1E000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 public constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 public constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 public constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 public constant FLAG_DISABLE_UNISWAP_POOL_TOKEN = 0x100000000; uint256 public constant FLAG_DISABLE_BALANCER_POOL_TOKEN = 0x200000000; uint256 public constant FLAG_DISABLE_CURVE_ZAP = 0x400000000; uint256 public constant FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN = 0x800000000; } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable; } // 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); function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256); function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); function getToken(address exchange) external view returns (IERC20 token); } // 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); function get_virtual_price() external view returns(uint256); // solium-disable-next-line mixedcase function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external; function coins(int128 arg0) external view returns (address); function balances(int128 arg0) external view returns (uint256); } // 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 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 toToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 toToken, 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.allowance(address(this), to) > 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)); } } // 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 toToken, uint amountIn ) internal view returns (uint256) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = toToken.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/OneSplitBase.sol pragma solidity ^0.5.0; //import "./interface/IBancorNetworkPathFinder.sol"; contract IOneSplitView is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); } library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns(bool) { return (flags & flag) != 0; } } contract OneSplitRoot { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20; using UniversalERC20 for IWETH; using UniversalERC20 for IBancorEtherToken; using UniswapV2ExchangeLib for IUniswapV2Exchange; using ChaiHelper for IChai; uint256 constant public DEXES_COUNT = 18; IERC20 constant public ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IERC20 constant public dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant public bnt = IERC20(0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C); IERC20 constant public usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant public usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant public tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant public busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant public susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant public pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IWETH constant public weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IBancorEtherToken constant public bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IChai constant public chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IKyberNetworkProxy constant public kyberNetworkProxy = IKyberNetworkProxy(0x818E6FECD516Ecc3849DAf6845e3EC868087B755); IUniswapFactory constant public uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant public bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); //IBancorNetworkPathFinder constant public bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); IBancorConverterRegistry constant public bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); IOasisExchange constant public oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D); ICurve constant public curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant public curveUsdt = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant public curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant public curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant public curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant public curvePax = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); IAaveLendingPool constant public aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); ICompound constant public compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); ICompoundEther constant public cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); IMooniswapRegistry constant public mooniswapRegistry = IMooniswapRegistry(0x7079E8517594e5b21d2B9a0D17cb33F5FE2bca70); IUniswapV2Factory constant public uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); function _buildBancorPath( IERC20 fromToken, IERC20 toToken ) internal view returns(address[] memory path) { if (fromToken == toToken) { return new address[](0); } if (fromToken.isETH()) { fromToken = bancorEtherToken; } if (toToken.isETH()) { toToken = bancorEtherToken; } if (fromToken == bnt || toToken == bnt) { path = new address[](3); } else { path = new address[](5); } address fromConverter; address toConverter; if (fromToken != bnt) { (bool success, bytes memory data) = address(bancorConverterRegistry).staticcall.gas(10000)(abi.encodeWithSelector( bancorConverterRegistry.getConvertibleTokenSmartToken.selector, fromToken.isETH() ? bnt : fromToken, 0 )); if (!success) { return new address[](0); } fromConverter = abi.decode(data, (address)); if (fromConverter == address(0)) { return new address[](0); } } if (toToken != bnt) { (bool success, bytes memory data) = address(bancorConverterRegistry).staticcall.gas(10000)(abi.encodeWithSelector( bancorConverterRegistry.getConvertibleTokenSmartToken.selector, toToken.isETH() ? bnt : toToken, 0 )); if (!success) { return new address[](0); } toConverter = abi.decode(data, (address)); if (toConverter == address(0)) { return new address[](0); } } if (toToken == 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(toToken); return path; } path[0] = address(fromToken); path[1] = fromConverter; path[2] = address(bnt); path[3] = toConverter; path[4] = address(toToken); 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 _infiniteApproveIfNeeded(IERC20 token, address to) internal { if (!token.isETH()) { if ((token.allowance(address(this), to) >> 255) == 0) { token.universalApprove(to, uint256(- 1)); } } } } contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return _getExpectedReturnFloor( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFloor( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) internal view returns( uint256 returnAmount, uint256[] memory distribution ); } contract OneSplitView is IOneSplitView, OneSplitRoot { function log(uint256) external view { } function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); if (fromToken == toToken) { return (amount, distribution); } bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); function(IERC20,IERC20,uint256,uint256) view returns(uint256)[DEXES_COUNT] memory reserves = [ invert != flags.check(FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswapReturn, invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyberReturn, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancorReturn, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasisReturn, invert != flags.check(FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUsdt, invert != flags.check(FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, (true) != flags.check(FLAG_ENABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, (true) != flags.check(FLAG_ENABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, (true) != flags.check(FLAG_ENABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePax ]; uint256[DEXES_COUNT] memory rates; uint256[DEXES_COUNT] memory fullRates; for (uint i = 0; i < rates.length; i++) { rates[i] = reserves[i](fromToken, toToken, amount.div(parts), flags); this.log(rates[i]); fullRates[i] = rates[i]; } for (uint j = 0; j < parts; j++) { // Find best part uint256 bestIndex = 0; for (uint i = 1; i < rates.length; i++) { if (rates[i] > rates[bestIndex]) { bestIndex = i; } } // Add best part returnAmount = returnAmount.add(rates[bestIndex]); distribution[bestIndex]++; // Avoid CompilerError: Stack too deep uint256 srcAmount = amount; // Recalc part if needed if (j + 1 < parts) { uint256 newRate = reserves[bestIndex]( fromToken, toToken, srcAmount.mul(distribution[bestIndex] + 1).div(parts), flags ); if (newRate > fullRates[bestIndex]) { rates[bestIndex] = newRate.sub(fullRates[bestIndex]); } else { rates[bestIndex] = 0; } this.log(rates[bestIndex]); fullRates[bestIndex] = newRate; } } } // View Helpers function calculateCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curveCompound.get_dy_underlying(i - 1, j - 1, amount); } function calculateCurveUsdt( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curveUsdt.get_dy_underlying(i - 1, j - 1, amount); } function calculateCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curveY.get_dy_underlying(i - 1, j - 1, amount); } function calculateCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curveBinance.get_dy_underlying(i - 1, j - 1, amount); } function calculateCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curveSynthetix.get_dy_underlying(i - 1, j - 1, amount); } function calculateCurvePax( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) public view 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; } return curvePax.get_dy_underlying(i - 1, j - 1, amount); } function calculateUniswapReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*flags*/ ) public view returns(uint256) { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { (bool success, bytes memory data) = address(fromExchange).staticcall.gas(200000)( abi.encodeWithSelector( fromExchange.getTokenToEthInputPrice.selector, returnAmount ) ); if (success) { returnAmount = abi.decode(data, (uint256)); } else { returnAmount = 0; } } else { returnAmount = 0; } } if (!toToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(toToken); if (toExchange != IUniswapExchange(0)) { (bool success, bytes memory data) = address(toExchange).staticcall.gas(200000)( abi.encodeWithSelector( toExchange.getEthToTokenInputPrice.selector, returnAmount ) ); if (success) { returnAmount = abi.decode(data, (uint256)); } else { returnAmount = 0; } } else { returnAmount = 0; } } return returnAmount; } function calculateUniswapCompound( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (!fromToken.isETH() && !toToken.isETH()) { return 0; } if (!fromToken.isETH()) { ICompoundToken fromCompound = _getCompoundToken(fromToken); if (fromCompound != ICompoundToken(0)) { return calculateUniswapReturn( fromCompound, toToken, amount.mul(1e18).div(fromCompound.exchangeRateStored()), flags ); } } else { ICompoundToken toCompound = _getCompoundToken(toToken); if (toCompound != ICompoundToken(0)) { return calculateUniswapReturn( fromToken, toCompound, amount, flags ).mul(toCompound.exchangeRateStored()).div(1e18); } } return 0; } function calculateUniswapChai( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (fromToken == dai && toToken.isETH()) { return calculateUniswapReturn( chai, toToken, chai.daiToChai(amount), flags ); } if (fromToken.isETH() && toToken == dai) { return chai.chaiToDai(calculateUniswapReturn( fromToken, chai, amount, flags )); } return 0; } function calculateUniswapAave( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (!fromToken.isETH() && !toToken.isETH()) { return 0; } if (!fromToken.isETH()) { IAaveToken fromAave = _getAaveToken(fromToken); if (fromAave != IAaveToken(0)) { return calculateUniswapReturn( fromAave, toToken, amount, flags ); } } else { IAaveToken toAave = _getAaveToken(toToken); if (toAave != IAaveToken(0)) { return calculateUniswapReturn( fromToken, toAave, amount, flags ); } } return 0; } function calculateKyberReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { (bool success, bytes memory data) = address(kyberNetworkProxy).staticcall.gas(2300)(abi.encodeWithSelector( kyberNetworkProxy.kyberNetworkContract.selector )); if (!success) { return 0; } IKyberNetworkContract kyberNetworkContract = IKyberNetworkContract(abi.decode(data, (address))); if (fromToken.isETH() || toToken.isETH()) { return _calculateKyberReturnWithEth(kyberNetworkContract, fromToken, toToken, amount, flags); } uint256 value = _calculateKyberReturnWithEth(kyberNetworkContract, fromToken, ETH_ADDRESS, amount, flags); if (value == 0) { return 0; } return _calculateKyberReturnWithEth(kyberNetworkContract, ETH_ADDRESS, toToken, value, flags); } function _calculateKyberReturnWithEth( IKyberNetworkContract kyberNetworkContract, IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { require(fromToken.isETH() || toToken.isETH(), "One of the tokens should be ETH"); (bool success, bytes memory data) = address(kyberNetworkContract).staticcall.gas(1500000)(abi.encodeWithSelector( kyberNetworkContract.searchBestRate.selector, fromToken.isETH() ? ETH_ADDRESS : fromToken, toToken.isETH() ? ETH_ADDRESS : toToken, amount, true )); if (!success) { return 0; } (address reserve, uint256 rate) = abi.decode(data, (address,uint256)); if (rate == 0) { return 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; } if (!flags.check(FLAG_ENABLE_KYBER_UNISWAP_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberUniswapReserve(reserve).uniswapFactory.selector )); if (success) { return 0; } } if (!flags.check(FLAG_ENABLE_KYBER_OASIS_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberOasisReserve(reserve).otc.selector )); if (success) { return 0; } } if (!flags.check(FLAG_ENABLE_KYBER_BANCOR_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberBancorReserve(reserve).bancorEth.selector )); if (success) { return 0; } } return rate.mul(amount) .mul(10 ** IERC20(toToken).universalDecimals()) .div(10 ** IERC20(fromToken).universalDecimals()) .div(1e18); } function calculateBancorReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*flags*/ ) public view returns(uint256) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = _buildBancorPath(fromToken, toToken); (bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)( abi.encodeWithSelector( bancorNetwork.getReturnByPath.selector, path, amount ) ); if (!success) { return 0; } (uint256 returnAmount,) = abi.decode(data, (uint256,uint256)); return returnAmount; } function calculateOasisReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*flags*/ ) public view returns(uint256) { (bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)( abi.encodeWithSelector( oasisExchange.getBuyAmount.selector, toToken.isETH() ? weth : toToken, fromToken.isETH() ? weth : fromToken, amount ) ); if (!success) { return 0; } return abi.decode(data, (uint256)); } function calculateMooniswap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*flags*/ ) public view returns(uint256) { IMooniswap mooniswap = mooniswapRegistry.target(); (bool success, bytes memory data) = address(mooniswap).staticcall.gas(1000000)( abi.encodeWithSelector( mooniswap.getReturn.selector, fromToken, toToken, amount ) ); if (!success) { return 0; } return abi.decode(data, (uint256)); } function calculateUniswapV2( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*flags*/ ) public view returns(uint256) { IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = toToken.isETH() ? weth : toToken; IUniswapV2Exchange fromExchange = uniswapV2.getPair(fromTokenReal, toTokenReal); if (fromExchange != IUniswapV2Exchange(0)) { return fromExchange.getReturn(fromTokenReal, toTokenReal, amount); } } function calculateUniswapV2ETH( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (fromToken.isETH() || fromToken == weth || toToken.isETH() || toToken == weth) { return 0; } return calculateUniswapV2OverMidToken( fromToken, weth, toToken, amount, flags ); } function calculateUniswapV2DAI( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (fromToken == dai || toToken == dai) { return 0; } return calculateUniswapV2OverMidToken( fromToken, dai, toToken, amount, flags ); } function calculateUniswapV2USDC( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { if (fromToken == usdc || toToken == usdc) { return 0; } return calculateUniswapV2OverMidToken( fromToken, usdc, toToken, amount, flags ); } function calculateUniswapV2OverMidToken( IERC20 fromToken, IERC20 midToken, IERC20 toToken, uint256 amount, uint256 flags ) public view returns(uint256) { return calculateUniswapV2( midToken, toToken, calculateUniswapV2(fromToken, midToken, amount, flags), flags ); } function _calculateNoReturn( IERC20 /*fromToken*/, IERC20 /*toToken*/, uint256 /*amount*/, uint256 /*flags*/ ) internal view returns(uint256) { this; } } contract OneSplitBaseWrap is IOneSplit, OneSplitRoot { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) internal { if (fromToken == toToken) { return; } _swapFloor( fromToken, toToken, amount, distribution, flags ); } function _swapFloor( IERC20 fromToken, IERC20 toToken, 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 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 /*minReturn*/, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) public payable { if (fromToken == toToken) { return; } 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 ]; 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; } } require(parts > 0, "OneSplit: distribution should contain non-zeros"); uint256 remainingAmount = amount; 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, toToken, swapAmount); } } // 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; } _infiniteApproveIfNeeded(fromToken, address(curveCompound)); 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; } _infiniteApproveIfNeeded(fromToken, address(curveUsdt)); 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; } _infiniteApproveIfNeeded(fromToken, address(curveY)); 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; } _infiniteApproveIfNeeded(fromToken, address(curveBinance)); 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; } _infiniteApproveIfNeeded(fromToken, address(curveSynthetix)); 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; } _infiniteApproveIfNeeded(fromToken, address(curvePax)); curvePax.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnUniswap( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { _infiniteApproveIfNeeded(fromToken, address(fromExchange)); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!toToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(toToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } return returnAmount; } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { ICompoundToken fromCompound = _getCompoundToken(fromToken); _infiniteApproveIfNeeded(fromToken, address(fromCompound)); fromCompound.mint(amount); return _swapOnUniswap(IERC20(fromCompound), toToken, IERC20(fromCompound).universalBalanceOf(address(this))); } if (!toToken.isETH()) { ICompoundToken toCompound = _getCompoundToken(toToken); uint256 compoundAmount = _swapOnUniswap(fromToken, IERC20(toCompound), amount); toCompound.redeem(compoundAmount); return toToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapChai( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { if (fromToken == dai) { _infiniteApproveIfNeeded(fromToken, address(chai)); chai.join(address(this), amount); return _swapOnUniswap(IERC20(chai), toToken, IERC20(chai).universalBalanceOf(address(this))); } if (toToken == dai) { uint256 chaiAmount = _swapOnUniswap(fromToken, IERC20(chai), amount); chai.exit(address(this), chaiAmount); return toToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapAave( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { IAaveToken fromAave = _getAaveToken(fromToken); _infiniteApproveIfNeeded(fromToken, address(fromAave)); aave.deposit(fromToken, amount, 1101); return _swapOnUniswap(IERC20(fromAave), toToken, IERC20(fromAave).universalBalanceOf(address(this))); } if (!toToken.isETH()) { IAaveToken toAave = _getAaveToken(toToken); uint256 aaveAmount = _swapOnUniswap(fromToken, IERC20(toAave), amount); toAave.redeem(aaveAmount); return aaveAmount; } return 0; } function _swapOnMooniswap( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { IMooniswap mooniswap = mooniswapRegistry.target(); _infiniteApproveIfNeeded(fromToken, address(mooniswap)); return mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken, toToken, amount, 0 ); } function _swapOnKyber( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { _infiniteApproveIfNeeded(fromToken, address(kyberNetworkProxy)); return kyberNetworkProxy.tradeWithHint.value(fromToken.isETH() ? amount : 0)( fromToken.isETH() ? ETH_ADDRESS : fromToken, amount, toToken.isETH() ? ETH_ADDRESS : toToken, address(this), 1 << 255, 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, "" ); } function _swapOnBancor( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { if (fromToken.isETH()) { bancorEtherToken.deposit.value(amount)(); } IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = _buildBancorPath(fromToken, toToken); _infiniteApproveIfNeeded(fromToken.isETH() ? bancorEtherToken : fromToken, address(bancorNetwork)); uint256 returnAmount = bancorNetwork.claimAndConvert(path, amount, 1); if (toToken.isETH()) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); } return returnAmount; } function _swapOnOasis( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } _infiniteApproveIfNeeded(fromToken.isETH() ? weth : fromToken, address(oasisExchange)); uint256 returnAmount = oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, toToken.isETH() ? weth : toToken, 1 ); if (toToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } return returnAmount; } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = toToken.isETH() ? weth : toToken; 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 (toToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( midToken, toToken, _swapOnUniswapV2Internal( fromToken, midToken, amount ) ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( fromToken, toToken, amount ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, weth, toToken, amount ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, dai, toToken, amount ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 toToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, usdc, toToken, amount ); } } // File: contracts/OneSplitMultiPath.sol pragma solidity ^0.5.0; contract OneSplitMultiPathView is OneSplitViewWrapBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns ( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!fromToken.isETH() && !toToken.isETH() && flags.check(FLAG_ENABLE_MULTI_PATH_ETH)) { (returnAmount, distribution) = super.getExpectedReturn( fromToken, ETH_ADDRESS, amount, parts, flags | FLAG_DISABLE_BANCOR | FLAG_DISABLE_CURVE_COMPOUND | FLAG_DISABLE_CURVE_USDT | FLAG_DISABLE_CURVE_Y | FLAG_DISABLE_CURVE_BINANCE | FLAG_DISABLE_CURVE_PAX ); uint256[] memory dist; (returnAmount, dist) = super.getExpectedReturn( ETH_ADDRESS, toToken, returnAmount, parts, flags | FLAG_DISABLE_BANCOR | FLAG_DISABLE_CURVE_COMPOUND | FLAG_DISABLE_CURVE_USDT | FLAG_DISABLE_CURVE_Y | FLAG_DISABLE_CURVE_BINANCE | FLAG_DISABLE_CURVE_PAX ); for (uint i = 0; i < distribution.length; i++) { distribution[i] = distribution[i].add(dist[i] << 8); } return (returnAmount, distribution); } if (fromToken != dai && toToken != dai && flags.check(FLAG_ENABLE_MULTI_PATH_DAI)) { (returnAmount, distribution) = super.getExpectedReturn( fromToken, dai, amount, parts, flags ); uint256[] memory dist; (returnAmount, dist) = super.getExpectedReturn( dai, toToken, returnAmount, parts, flags ); for (uint i = 0; i < distribution.length; i++) { distribution[i] = distribution[i].add(dist[i] << 8); } return (returnAmount, distribution); } if (fromToken != usdc && toToken != usdc && flags.check(FLAG_ENABLE_MULTI_PATH_USDC)) { (returnAmount, distribution) = super.getExpectedReturn( fromToken, usdc, amount, parts, flags ); uint256[] memory dist; (returnAmount, dist) = super.getExpectedReturn( usdc, toToken, returnAmount, parts, flags ); for (uint i = 0; i < distribution.length; i++) { distribution[i] = distribution[i].add(dist[i] << 8); } return (returnAmount, distribution); } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitMultiPath is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!fromToken.isETH() && !toToken.isETH() && flags.check(FLAG_ENABLE_MULTI_PATH_ETH)) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & 0xFF; } super._swap( fromToken, ETH_ADDRESS, amount, dist, flags ); for (uint i = 0; i < distribution.length; i++) { dist[i] = (distribution[i] >> 8) & 0xFF; } super._swap( ETH_ADDRESS, toToken, address(this).balance, dist, flags ); return; } if (fromToken != dai && toToken != dai && flags.check(FLAG_ENABLE_MULTI_PATH_DAI)) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & 0xFF; } super._swap( fromToken, dai, amount, dist, flags ); for (uint i = 0; i < distribution.length; i++) { dist[i] = (distribution[i] >> 8) & 0xFF; } super._swap( dai, toToken, dai.balanceOf(address(this)), dist, flags ); return; } if (fromToken != usdc && toToken != usdc && flags.check(FLAG_ENABLE_MULTI_PATH_USDC)) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & 0xFF; } super._swap( fromToken, usdc, amount, dist, flags ); for (uint i = 0; i < distribution.length; i++) { dist[i] = (distribution[i] >> 8) & 0xFF; } super._swap( usdc, toToken, usdc.balanceOf(address(this)), dist, flags ); return; } super._swap( fromToken, toToken, 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 getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = _getCompoundUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); return _compoundGetExpectedReturn( underlying, toToken, amount.mul(compoundRate).div(1e18), parts, flags ); } underlying = _getCompoundUnderlyingToken(toToken); if (underlying != IERC20(-1)) { uint256 compoundRate = ICompoundToken(address(toToken)).exchangeRateStored(); (returnAmount, distribution) = super.getExpectedReturn( fromToken, underlying, amount, parts, flags ); returnAmount = returnAmount.mul(1e18).div(compoundRate); return (returnAmount, distribution); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitCompound is OneSplitBaseWrap, OneSplitCompoundBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compundSwap( fromToken, toToken, amount, distribution, flags ); } function _compundSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == toToken) { return; } if (!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 _compundSwap( underlying, toToken, underlyingAmount, distribution, flags ); } underlying = _getCompoundUnderlyingToken(toToken); 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 { _infiniteApproveIfNeeded(underlying, address(toToken)); ICompoundToken(address(toToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, toToken, amount, distribution, flags ); } } // File: @openzeppelin/contracts/token/ERC20/ERC20Detailed.sol pragma solidity ^0.5.0; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } } // 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) public view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( ERC20Detailed(address(token)).name.selector )); 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 getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); return _fulcrumGetExpectedReturn( underlying, toToken, amount.mul(fulcrumRate).div(1e18), parts, flags ); } underlying = _isFulcrumToken(toToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(toToken)).tokenPrice(); (returnAmount, distribution) = super.getExpectedReturn( fromToken, underlying, amount, parts, flags ); returnAmount = returnAmount.mul(1e18).div(fulcrumRate); return (returnAmount, distribution); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, toToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == toToken) { return; } if (!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, toToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(toToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(toToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { _infiniteApproveIfNeeded(underlying, address(toToken)); IFulcrumToken(address(toToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, toToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { return super.getExpectedReturn( dai, toToken, chai.chaiToDai(amount), parts, flags ); } if (toToken == IERC20(chai)) { (returnAmount, distribution) = super.getExpectedReturn( fromToken, dai, amount, parts, flags ); return (chai.daiToChai(returnAmount), distribution); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, toToken, dai.balanceOf(address(this)), distribution, flags ); } if (toToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); _infiniteApproveIfNeeded(dai, address(chai)); chai.join(address(this), dai.balanceOf(address(this))); return; } } return super._swap( fromToken, toToken, 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 public bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 public btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns (uint256 returnAmount, uint256[] memory distribution) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { return super.getExpectedReturn( dai, toToken, amount, parts, flags ); } if (toToken == IERC20(bdai)) { return super.getExpectedReturn( fromToken, dai, amount, parts, flags ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!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, toToken, btuBalance, 1, flags ); _swap( btu, toToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, toToken, amount, distribution, flags ); } if (toToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); _infiniteApproveIfNeeded(dai, address(bdai)); bdai.join(dai.balanceOf(address(this))); return; } } return super._swap(fromToken, toToken, 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 getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns (uint256 returnAmount, uint256[] memory distribution) { return _iearnGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } IIearn[13] memory yTokens = _yTokens(); if (!flags.check(FLAG_DISABLE_IEARN)) { for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { return _iearnGetExpectedReturn( yTokens[i].token(), toToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags ); } } for (uint i = 0; i < yTokens.length; i++) { if (toToken == IERC20(yTokens[i])) { (uint256 ret, uint256[] memory dist) = super.getExpectedReturn( fromToken, yTokens[i].token(), amount, parts, flags ); return ( ret .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), dist ); } } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, toToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == toToken) { return; } IIearn[13] memory yTokens = _yTokens(); if (!flags.check(FLAG_DISABLE_IEARN)) { for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, toToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (toToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); _infiniteApproveIfNeeded(underlying, address(yTokens[i])); yTokens[i].deposit(underlying.balanceOf(address(this))); return; } } } return super._swap(fromToken, toToken, 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[2] memory) { return [ IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns (uint256 /*returnAmount*/, uint256[] memory /*distribution*/) { return _idleGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns (uint256 returnAmount, uint256[] memory distribution) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } IIdle[2] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { return _idleGetExpectedReturn( tokens[i].token(), toToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags ); } } for (uint i = 0; i < tokens.length; i++) { if (toToken == IERC20(tokens[i])) { (uint256 ret, uint256[] memory dist) = super.getExpectedReturn( fromToken, tokens[i].token(), amount, parts, flags ); return ( ret.mul(1e18).div(tokens[i].tokenPrice()), dist ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _superOneSplitIdleSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] calldata distribution, uint256 flags ) external { require(msg.sender == address(this)); return super._swap(fromToken, toToken, amount, distribution, flags); } function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, toToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) public payable { IIdle[2] 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, toToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (toToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); _infiniteApproveIfNeeded(underlying, address(tokens[i])); tokens[i].mintIdleToken(underlying.balanceOf(address(this)), new uint256[](0)); return; } } return super._swap(fromToken, toToken, 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 getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, distribution); } if (!flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { return _aaveGetExpectedReturn( underlying, toToken, amount, parts, flags ); } underlying = _getAaveUnderlyingToken(toToken); if (underlying != IERC20(-1)) { return super.getExpectedReturn( fromToken, underlying, amount, parts, flags ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitAave is OneSplitBaseWrap, OneSplitAaveBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, toToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, toToken, amount, distribution, flags ); } underlying = _getAaveUnderlyingToken(toToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); _infiniteApproveIfNeeded(underlying, aave.core()); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, toToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturn(ETH_ADDRESS, toToken, amount, parts, flags); } if (toToken == weth || toToken == bancorEtherToken) { return super.getExpectedReturn(fromToken, ETH_ADDRESS, amount, parts, flags); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, toToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, toToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, toToken, amount, distribution, flags ); return; } if (toToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (toToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, toToken, amount, distribution, flags ); } } // File: contracts/interface/IBFactory.sol pragma solidity ^0.5.0; interface IBFactory { function isBPool(address b) external view returns (bool); } // File: contracts/interface/IBPool.sol pragma solidity ^0.5.0; contract BConst { uint public constant EXIT_FEE = 0; } contract IBMath is BConst { function calcPoolOutGivenSingleIn( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint tokenAmountIn, uint swapFee ) public pure returns (uint poolAmountOut); } contract IBPool is IERC20, IBMath { function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; function exitPool(uint poolAmountIn, uint[] calldata minAmountsOut) external; function joinswapExternAmountIn(address tokenIn, uint tokenAmountIn, uint minPoolAmountOut) external returns (uint poolAmountOut); function getCurrentTokens() external view returns (address[] memory tokens); function getBalance(address token) external view returns (uint); function getNormalizedWeight(address token) external view returns (uint); function getDenormalizedWeight(address token) external view returns (uint); function getTotalDenormalizedWeight() external view returns (uint); function getSwapFee() external view returns (uint); } // File: contracts/OneSplitBalancerPoolToken.sol pragma solidity ^0.5.0; contract OneSplitBalancerPoolTokenBase { using SafeMath for uint256; // todo: factory for Bronze release // may be changed in future IBFactory bFactory = IBFactory(0x9424B1412450D0f8Fc2255FAf6046b98213B76Bd); struct TokenWithWeight { IERC20 token; uint256 reserveBalance; uint256 denormalizedWeight; } struct PoolTokenDetails { TokenWithWeight[] tokens; uint256 totalWeight; uint256 totalSupply; } function _getPoolDetails(IBPool poolToken) internal view returns(PoolTokenDetails memory details) { address[] memory currentTokens = poolToken.getCurrentTokens(); details.tokens = new TokenWithWeight[](currentTokens.length); details.totalWeight = poolToken.getTotalDenormalizedWeight(); details.totalSupply = poolToken.totalSupply(); for (uint256 i = 0; i < details.tokens.length; i++) { details.tokens[i].token = IERC20(currentTokens[i]); details.tokens[i].denormalizedWeight = poolToken.getDenormalizedWeight(currentTokens[i]); details.tokens[i].reserveBalance = poolToken.getBalance(currentTokens[i]); } } } contract OneSplitBalancerPoolTokenView is OneSplitViewWrapBase, OneSplitBalancerPoolTokenBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns ( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_BALANCER_POOL_TOKEN)) { bool isPoolTokenFrom = bFactory.isBPool(address(fromToken)); bool isPoolTokenTo = bFactory.isBPool(address(toToken)); if (isPoolTokenFrom && isPoolTokenTo) { ( uint256 returnETHAmount, uint256[] memory poolTokenFromDistribution ) = _getExpectedReturnFromBalancerPoolToken( fromToken, ETH_ADDRESS, amount, parts, FLAG_DISABLE_BALANCER_POOL_TOKEN ); ( uint256 returnPoolTokenToAmount, uint256[] memory poolTokenToDistribution ) = _getExpectedReturnToBalancerPoolToken( ETH_ADDRESS, toToken, returnETHAmount, parts, FLAG_DISABLE_BALANCER_POOL_TOKEN ); for (uint i = 0; i < poolTokenToDistribution.length; i++) { poolTokenFromDistribution[i] |= poolTokenToDistribution[i] << 128; } return (returnPoolTokenToAmount, poolTokenFromDistribution); } if (isPoolTokenFrom) { return _getExpectedReturnFromBalancerPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_BALANCER_POOL_TOKEN ); } if (isPoolTokenTo) { return _getExpectedReturnToBalancerPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_BALANCER_POOL_TOKEN ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFromBalancerPoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns ( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); IBPool bToken = IBPool(address(poolToken)); address[] memory currentTokens = bToken.getCurrentTokens(); uint256 pAiAfterExitFee = amount.sub( amount.mul(bToken.EXIT_FEE()) ); uint256 ratio = pAiAfterExitFee.mul(1e18).div(poolToken.totalSupply()); for (uint i = 0; i < currentTokens.length; i++) { uint256 tokenAmountOut = bToken.getBalance(currentTokens[i]).mul(ratio).div(1e18); if (currentTokens[i] == address(toToken)) { returnAmount = returnAmount.add(tokenAmountOut); continue; } (uint256 ret, uint256[] memory dist) = getExpectedReturn( IERC20(currentTokens[i]), toToken, tokenAmountOut, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } return (returnAmount, distribution); } function _getExpectedReturnToBalancerPoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256 parts, uint256 flags ) private view returns ( uint256 minFundAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); minFundAmount = uint256(-1); PoolTokenDetails memory details = _getPoolDetails(IBPool(address(poolToken))); uint256[] memory tokenAmounts = new uint256[](details.tokens.length); uint256[] memory dist; uint256[] memory fundAmounts = new uint256[](details.tokens.length); for (uint i = 0; i < details.tokens.length; i++) { uint256 exchangeAmount = amount.mul( details.tokens[i].denormalizedWeight ).div(details.totalWeight); if (details.tokens[i].token != fromToken) { (tokenAmounts[i], dist) = getExpectedReturn( fromToken, details.tokens[i].token, exchangeAmount, parts, flags ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } else { tokenAmounts[i] = exchangeAmount; } fundAmounts[i] = tokenAmounts[i] .mul(details.totalSupply) .div(details.tokens[i].reserveBalance); if (fundAmounts[i] < minFundAmount) { minFundAmount = fundAmounts[i]; } } // uint256 _minFundAmount = minFundAmount; // uint256 swapFee = IBPool(address(poolToken)).getSwapFee(); // Swap leftovers for PoolToken // for (uint i = 0; i < details.tokens.length; i++) { // if (_minFundAmount == fundAmounts[i]) { // continue; // } // // uint256 leftover = tokenAmounts[i].sub( // fundAmounts[i].mul(details.tokens[i].reserveBalance).div(details.totalSupply) // ); // // uint256 tokenRet = IBPool(address(poolToken)).calcPoolOutGivenSingleIn( // details.tokens[i].reserveBalance, // details.tokens[i].denormalizedWeight, // details.totalSupply, // details.totalWeight, // leftover, // swapFee // ); // // minFundAmount = minFundAmount.add(tokenRet); // } return (minFundAmount, distribution); } } contract OneSplitBalancerPoolToken is OneSplitBaseWrap, OneSplitBalancerPoolTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_BALANCER_POOL_TOKEN)) { bool isPoolTokenFrom = bFactory.isBPool(address(fromToken)); bool isPoolTokenTo = bFactory.isBPool(address(toToken)); if (isPoolTokenFrom && isPoolTokenTo) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & ((1 << 128) - 1); } uint256 ethBalanceBefore = address(this).balance; _swapFromBalancerPoolToken( fromToken, ETH_ADDRESS, amount, dist, FLAG_DISABLE_BALANCER_POOL_TOKEN ); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] >> 128; } uint256 ethBalanceAfter = address(this).balance; return _swapToBalancerPoolToken( ETH_ADDRESS, toToken, ethBalanceAfter.sub(ethBalanceBefore), dist, FLAG_DISABLE_BALANCER_POOL_TOKEN ); } if (isPoolTokenFrom) { return _swapFromBalancerPoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_BALANCER_POOL_TOKEN ); } if (isPoolTokenTo) { return _swapToBalancerPoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_BALANCER_POOL_TOKEN ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromBalancerPoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { IBPool bToken = IBPool(address(poolToken)); address[] memory currentTokens = bToken.getCurrentTokens(); uint256 ratio = amount.sub( amount.mul(bToken.EXIT_FEE()) ).mul(1e18).div(poolToken.totalSupply()); uint256[] memory minAmountsOut = new uint256[](currentTokens.length); for (uint i = 0; i < currentTokens.length; i++) { minAmountsOut[i] = bToken.getBalance(currentTokens[i]).mul(ratio).div(1e18).mul(995).div(1000); // 0.5% slippage; } bToken.exitPool(amount, minAmountsOut); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < currentTokens.length; i++) { if (currentTokens[i] == address(toToken)) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } uint256 exchangeTokenAmount = IERC20(currentTokens[i]).balanceOf(address(this)); this.swap( IERC20(currentTokens[i]), toToken, exchangeTokenAmount, 0, dist, flags ); } } function _swapToBalancerPoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { uint256[] memory dist = new uint256[](distribution.length); uint256 minFundAmount = uint256(-1); PoolTokenDetails memory details = _getPoolDetails(IBPool(address(poolToken))); uint256[] memory maxAmountsIn = new uint256[](details.tokens.length); uint256 curFundAmount; for (uint i = 0; i < details.tokens.length; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].denormalizedWeight) .div(details.totalWeight); if (details.tokens[i].token != fromToken) { uint256 tokenBalanceBefore = details.tokens[i].token.balanceOf(address(this)); for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( fromToken, details.tokens[i].token, exchangeAmount, 0, dist, flags ); uint256 tokenBalanceAfter = details.tokens[i].token.balanceOf(address(this)); curFundAmount = ( tokenBalanceAfter.sub(tokenBalanceBefore) ).mul(details.totalSupply).div(details.tokens[i].reserveBalance); } else { curFundAmount = ( exchangeAmount ).mul(details.totalSupply).div(details.tokens[i].reserveBalance); } if (curFundAmount < minFundAmount) { minFundAmount = curFundAmount; } maxAmountsIn[i] = uint256(-1); _infiniteApproveIfNeeded(details.tokens[i].token, address(poolToken)); } // todo: check for vulnerability IBPool(address(poolToken)).joinPool(minFundAmount, maxAmountsIn); // Return leftovers for (uint i = 0; i < details.tokens.length; i++) { details.tokens[i].token.universalTransfer(msg.sender, details.tokens[i].token.balanceOf(address(this))); } } } // File: contracts/OneSplitUniswapPoolToken.sol pragma solidity ^0.5.0; contract OneSplitUniswapPoolTokenBase { using SafeMath for uint256; IUniswapFactory constant uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); function isLiquidityPool(IERC20 token) internal view returns (bool) { return address(uniswapFactory.getToken(address(token))) != address(0); } function getMaxPossibleFund( IERC20 poolToken, IERC20 uniswapToken, uint256 tokenAmount, uint256 existEthAmount ) internal view returns ( uint256, uint256 ) { uint256 ethReserve = address(poolToken).balance; uint256 totalLiquidity = poolToken.totalSupply(); uint256 tokenReserve = uniswapToken.balanceOf(address(poolToken)); uint256 possibleEthAmount = ethReserve.mul( tokenAmount.sub(1) ).div(tokenReserve); if (existEthAmount > possibleEthAmount) { return ( possibleEthAmount, possibleEthAmount.mul(totalLiquidity).div(ethReserve) ); } return ( existEthAmount, existEthAmount.mul(totalLiquidity).div(ethReserve) ); } } contract OneSplitUniswapPoolTokenView is OneSplitViewWrapBase, OneSplitUniswapPoolTokenBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_UNISWAP_POOL_TOKEN)) { bool isPoolTokenFrom = isLiquidityPool(fromToken); bool isPoolTokenTo = isLiquidityPool(toToken); if (isPoolTokenFrom && isPoolTokenTo) { ( uint256 returnETHAmount, uint256[] memory poolTokenFromDistribution ) = _getExpectedReturnFromPoolToken( fromToken, ETH_ADDRESS, amount, parts, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); ( uint256 returnPoolTokenToAmount, uint256[] memory poolTokenToDistribution ) = _getExpectedReturnToPoolToken( ETH_ADDRESS, toToken, returnETHAmount, parts, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); for (uint i = 0; i < poolTokenToDistribution.length; i++) { poolTokenFromDistribution[i] |= poolTokenToDistribution[i] << 128; } return (returnPoolTokenToAmount, poolTokenFromDistribution); } if (isPoolTokenFrom) { return _getExpectedReturnFromPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); } if (isPoolTokenTo) { return _getExpectedReturnToPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFromPoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); IERC20 uniswapToken = uniswapFactory.getToken(address(poolToken)); uint256 totalSupply = poolToken.totalSupply(); uint256 ethReserve = address(poolToken).balance; uint256 ethAmount = amount.mul(ethReserve).div(totalSupply); if (!toToken.isETH()) { (uint256 ret, uint256[] memory dist) = getExpectedReturn( ETH_ADDRESS, toToken, ethAmount, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j]; } } else { returnAmount = returnAmount.add(ethAmount); } uint256 tokenReserve = uniswapToken.balanceOf(address(poolToken)); uint256 exchangeTokenAmount = amount.mul(tokenReserve).div(totalSupply); if (toToken != uniswapToken) { (uint256 ret, uint256[] memory dist) = getExpectedReturn( uniswapToken, toToken, exchangeTokenAmount, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << 8; } } else { returnAmount = returnAmount.add(exchangeTokenAmount); } return (returnAmount, distribution); } function _getExpectedReturnToPoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); uint256[] memory dist = new uint256[](DEXES_COUNT); uint256 ethAmount; uint256 partAmountForEth = amount.div(2); if (!fromToken.isETH()) { (ethAmount, dist) = super.getExpectedReturn( fromToken, ETH_ADDRESS, partAmountForEth, parts, flags ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j]; } } else { ethAmount = partAmountForEth; } IERC20 uniswapToken = uniswapFactory.getToken(address(poolToken)); uint256 tokenAmount; uint256 partAmountForToken = amount.sub(partAmountForEth); if (fromToken != uniswapToken) { (tokenAmount, dist) = super.getExpectedReturn( fromToken, uniswapToken, partAmountForToken, parts, flags ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << 8; } } else { tokenAmount = partAmountForToken; } (, returnAmount) = getMaxPossibleFund( poolToken, uniswapToken, tokenAmount, ethAmount ); return ( returnAmount, distribution ); } } contract OneSplitUniswapPoolToken is OneSplitBaseWrap, OneSplitUniswapPoolTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_UNISWAP_POOL_TOKEN)) { bool isPoolTokenFrom = isLiquidityPool(fromToken); bool isPoolTokenTo = isLiquidityPool(toToken); if (isPoolTokenFrom && isPoolTokenTo) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & ((1 << 128) - 1); } uint256 ethBalanceBefore = address(this).balance; _swapFromPoolToken( fromToken, ETH_ADDRESS, amount, dist, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] >> 128; } uint256 ethBalanceAfter = address(this).balance; return _swapToPoolToken( ETH_ADDRESS, toToken, ethBalanceAfter.sub(ethBalanceBefore), dist, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); } if (isPoolTokenFrom) { return _swapFromPoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); } if (isPoolTokenTo) { return _swapToPoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_UNISWAP_POOL_TOKEN ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromPoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { uint256[] memory dist = new uint256[](distribution.length); ( uint256 ethAmount, uint256 exchangeTokenAmount ) = IUniswapExchange(address(poolToken)).removeLiquidity( amount, 1, 1, now.add(1800) ); if (!toToken.isETH()) { for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j]) & 0xFF; } super._swap( ETH_ADDRESS, toToken, ethAmount, dist, flags ); } IERC20 uniswapToken = uniswapFactory.getToken(address(poolToken)); if (toToken != uniswapToken) { for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> 8) & 0xFF; } super._swap( uniswapToken, toToken, exchangeTokenAmount, dist, flags ); } } function _swapToPoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { uint256[] memory dist = new uint256[](distribution.length); uint256 partAmountForEth = amount.div(2); if (!fromToken.isETH()) { for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j]) & 0xFF; } super._swap( fromToken, ETH_ADDRESS, partAmountForEth, dist, flags ); } IERC20 uniswapToken = uniswapFactory.getToken(address(poolToken)); uint256 partAmountForToken = amount.sub(partAmountForEth); if (fromToken != uniswapToken) { for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> 8) & 0xFF; } super._swap( fromToken, uniswapToken, partAmountForToken, dist, flags ); _infiniteApproveIfNeeded(uniswapToken, address(poolToken)); } uint256 ethBalance = address(this).balance; uint256 tokenBalance = uniswapToken.balanceOf(address(this)); (uint256 ethAmount, uint256 returnAmount) = getMaxPossibleFund( poolToken, uniswapToken, tokenBalance, ethBalance ); IUniswapExchange(address(poolToken)).addLiquidity.value(ethAmount)( returnAmount.mul(995).div(1000), // 0.5% slippage uint256(-1), // todo: think about another value now.add(1800) ); // todo: do we need to check difference between balance before and balance after? uniswapToken.universalTransfer(msg.sender, uniswapToken.balanceOf(address(this))); ETH_ADDRESS.universalTransfer(msg.sender, address(this).balance); } } // File: contracts/OneSplitCurvePoolToken.sol pragma solidity ^0.5.0; contract OneSplitCurvePoolTokenBase { using SafeMath for uint256; using UniversalERC20 for IERC20; IERC20 constant curveSusdToken = IERC20(0xC25a3A3b969415c80451098fa907EC722572917F); IERC20 constant curveIearnToken = IERC20(0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8); IERC20 constant curveCompoundToken = IERC20(0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2); IERC20 constant curveUsdtToken = IERC20(0x9fC689CCaDa600B6DF723D9E47D84d76664a1F23); IERC20 constant curveBinanceToken = IERC20(0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B); IERC20 constant curvePaxToken = IERC20(0xD905e2eaeBe188fc92179b6350807D8bd91Db0D8); IERC20 constant curveRenBtcToken = IERC20(0x7771F704490F9C0C3B06aFe8960dBB6c58CBC812); IERC20 constant curveTBtcToken = IERC20(0x1f2a662FB513441f06b8dB91ebD9a1466462b275); ICurve constant curveSusd = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant curveIearn = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant curveUsdt = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant curvePax = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); ICurve constant curveRenBtc = ICurve(0x8474c1236F0Bc23830A23a41aBB81B2764bA9f4F); ICurve constant curveTBtc = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E); struct CurveTokenInfo { IERC20 token; uint256 weightedReserveBalance; } struct CurveInfo { ICurve curve; uint256 tokenCount; } struct CurvePoolTokenDetails { CurveTokenInfo[] tokens; uint256 totalWeightedBalance; } function _isPoolToken(IERC20 token) internal pure returns (bool) { if ( token == curveSusdToken || token == curveIearnToken || token == curveCompoundToken || token == curveUsdtToken || token == curveBinanceToken || token == curvePaxToken || token == curveRenBtcToken || token == curveTBtcToken ) { return true; } return false; } function _getCurve(IERC20 poolToken) internal pure returns (CurveInfo memory curveInfo) { if (poolToken == curveSusdToken) { curveInfo.curve = curveSusd; curveInfo.tokenCount = 4; return curveInfo; } if (poolToken == curveIearnToken) { curveInfo.curve = curveIearn; curveInfo.tokenCount = 4; return curveInfo; } if (poolToken == curveCompoundToken) { curveInfo.curve = curveCompound; curveInfo.tokenCount = 2; return curveInfo; } if (poolToken == curveUsdtToken) { curveInfo.curve = curveUsdt; curveInfo.tokenCount = 3; return curveInfo; } if (poolToken == curveBinanceToken) { curveInfo.curve = curveBinance; curveInfo.tokenCount = 4; return curveInfo; } if (poolToken == curvePaxToken) { curveInfo.curve = curvePax; curveInfo.tokenCount = 4; return curveInfo; } if (poolToken == curveRenBtcToken) { curveInfo.curve = curveRenBtc; curveInfo.tokenCount = 2; return curveInfo; } if (poolToken == curveTBtcToken) { curveInfo.curve = curveTBtc; curveInfo.tokenCount = 3; return curveInfo; } revert(); } function _getCurveCalcTokenAmountSelector(uint256 tokenCount) internal pure returns (bytes4) { return bytes4(keccak256(abi.encodePacked( "calc_token_amount(uint256[", uint8(48 + tokenCount) ,"],bool)" ))); } function _getCurveRemoveLiquiditySelector(uint256 tokenCount) internal pure returns (bytes4) { return bytes4(keccak256(abi.encodePacked( "remove_liquidity(uint256,uint256[", uint8(48 + tokenCount) ,"])" ))); } function _getCurveAddLiquiditySelector(uint256 tokenCount) internal pure returns (bytes4) { return bytes4(keccak256(abi.encodePacked( "add_liquidity(uint256[", uint8(48 + tokenCount) ,"],uint256)" ))); } function _getPoolDetails(ICurve curve, uint256 tokenCount) internal view returns(CurvePoolTokenDetails memory details) { details.tokens = new CurveTokenInfo[](tokenCount); for (uint256 i = 0; i < tokenCount; i++) { details.tokens[i].token = IERC20(curve.coins(int128(i))); details.tokens[i].weightedReserveBalance = curve.balances(int128(i)) .mul(1e18).div(10 ** details.tokens[i].token.universalDecimals()); details.totalWeightedBalance = details.totalWeightedBalance.add( details.tokens[i].weightedReserveBalance ); } } } contract OneSplitCurvePoolTokenView is OneSplitViewWrapBase, OneSplitCurvePoolTokenBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns ( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_CURVE_ZAP)) { if (_isPoolToken(fromToken)) { return _getExpectedReturnFromCurvePoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_CURVE_ZAP ); } if (_isPoolToken(toToken)) { return _getExpectedReturnToCurvePoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_CURVE_ZAP ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFromCurvePoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns ( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); CurveInfo memory curveInfo = _getCurve(poolToken); uint256 totalSupply = poolToken.totalSupply(); for (uint i = 0; i < curveInfo.tokenCount; i++) { IERC20 coin = IERC20(curveInfo.curve.coins(int128(i))); uint256 tokenAmountOut = curveInfo.curve.balances(int128(i)) .mul(amount) .div(totalSupply); if (coin == toToken) { returnAmount = returnAmount.add(tokenAmountOut); continue; } (uint256 ret, uint256[] memory dist) = this.getExpectedReturn( coin, toToken, tokenAmountOut, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } return (returnAmount, distribution); } function _getExpectedReturnToCurvePoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256 parts, uint256 flags ) private view returns ( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); CurveInfo memory curveInfo = _getCurve(poolToken); CurvePoolTokenDetails memory details = _getPoolDetails( curveInfo.curve, curveInfo.tokenCount ); bytes memory tokenAmounts; for (uint i = 0; i < curveInfo.tokenCount; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].weightedReserveBalance) .div(details.totalWeightedBalance); if (details.tokens[i].token == fromToken) { tokenAmounts = abi.encodePacked(tokenAmounts, exchangeAmount); continue; } (uint256 tokenAmount, uint256[] memory dist) = this.getExpectedReturn( fromToken, details.tokens[i].token, exchangeAmount, parts, flags ); tokenAmounts = abi.encodePacked(tokenAmounts, tokenAmount); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } (bool success, bytes memory data) = address(curveInfo.curve).staticcall( abi.encodePacked( _getCurveCalcTokenAmountSelector(curveInfo.tokenCount), tokenAmounts, uint256(1) ) ); require(success, "calc_token_amount failed"); return (abi.decode(data, (uint256)), distribution); } } contract OneSplitCurvePoolToken is OneSplitBaseWrap, OneSplitCurvePoolTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_CURVE_ZAP)) { if (_isPoolToken(fromToken)) { return _swapFromCurvePoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_CURVE_ZAP ); } if (_isPoolToken(toToken)) { return _swapToCurvePoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_CURVE_ZAP ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromCurvePoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { CurveInfo memory curveInfo = _getCurve(poolToken); bytes memory minAmountsOut; for (uint i = 0; i < curveInfo.tokenCount; i++) { minAmountsOut = abi.encodePacked(minAmountsOut, uint256(1)); } (bool success,) = address(curveInfo.curve).call( abi.encodePacked( _getCurveRemoveLiquiditySelector(curveInfo.tokenCount), amount, minAmountsOut ) ); require(success, "remove_liquidity failed"); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < curveInfo.tokenCount; i++) { IERC20 coin = IERC20(curveInfo.curve.coins(int128(i))); if (coin == toToken) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } uint256 exchangeTokenAmount = coin.universalBalanceOf(address(this)); this.swap( coin, toToken, exchangeTokenAmount, 0, dist, flags ); } } function _swapToCurvePoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { uint256[] memory dist = new uint256[](distribution.length); CurveInfo memory curveInfo = _getCurve(poolToken); CurvePoolTokenDetails memory details = _getPoolDetails( curveInfo.curve, curveInfo.tokenCount ); bytes memory tokenAmounts; for (uint i = 0; i < curveInfo.tokenCount; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].weightedReserveBalance) .div(details.totalWeightedBalance); _infiniteApproveIfNeeded(details.tokens[i].token, address(curveInfo.curve)); if (details.tokens[i].token == fromToken) { tokenAmounts = abi.encodePacked(tokenAmounts, exchangeAmount); continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( fromToken, details.tokens[i].token, exchangeAmount, 0, dist, flags ); tokenAmounts = abi.encodePacked( tokenAmounts, details.tokens[i].token.universalBalanceOf(address(this)) ); } (bool success,) = address(curveInfo.curve).call( abi.encodePacked( _getCurveAddLiquiditySelector(curveInfo.tokenCount), tokenAmounts, uint256(0) ) ); require(success, "add_liquidity failed"); } } // File: contracts/interface/ISmartTokenConverter.sol pragma solidity ^0.5.0; interface ISmartTokenConverter { function version() external view returns (uint16); function connectors(address) external view returns (uint256, uint32, bool, bool, bool); function getReserveRatio(IERC20 token) external view returns (uint256); function connectorTokenCount() external view returns (uint256); function connectorTokens(uint256 i) external view returns (IERC20); function liquidate(uint256 _amount) external; function fund(uint256 _amount) external; function convert2(IERC20 _fromToken, IERC20 _toToken, uint256 _amount, uint256 _minReturn, address _affiliateAccount, uint256 _affiliateFee) external returns (uint256); function convert(IERC20 _fromToken, IERC20 _toToken, uint256 _amount, uint256 _minReturn) external returns (uint256); } // File: contracts/interface/ISmartToken.sol pragma solidity ^0.5.0; interface ISmartToken { function owner() external view returns (ISmartTokenConverter); } // File: contracts/interface/ISmartTokenRegistry.sol pragma solidity ^0.5.0; interface ISmartTokenRegistry { function isSmartToken(IERC20 token) external view returns (bool); } // File: contracts/interface/ISmartTokenFormula.sol pragma solidity ^0.5.0; interface ISmartTokenFormula { function calculateLiquidateReturn( uint256 supply, uint256 reserveBalance, uint32 totalRatio, uint256 amount ) external view returns (uint256); function calculatePurchaseReturn( uint256 supply, uint256 reserveBalance, uint32 totalRatio, uint256 amount ) external view returns (uint256); } // File: contracts/OneSplitSmartToken.sol pragma solidity ^0.5.0; contract OneSplitSmartTokenBase { using SafeMath for uint256; ISmartTokenRegistry constant smartTokenRegistry = ISmartTokenRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); ISmartTokenFormula constant smartTokenFormula = ISmartTokenFormula(0x524619EB9b4cdFFa7DA13029b33f24635478AFc0); IERC20 constant bntToken = IERC20(0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C); IERC20 constant usdbToken = IERC20(0x309627af60F0926daa6041B8279484312f2bf060); IERC20 constant susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant acientSUSD = IERC20(0x57Ab1E02fEE23774580C119740129eAC7081e9D3); struct TokenWithRatio { IERC20 token; uint256 ratio; } struct SmartTokenDetails { TokenWithRatio[] tokens; address converter; uint256 totalRatio; } function _getSmartTokenDetails(ISmartToken smartToken) internal view returns(SmartTokenDetails memory details) { ISmartTokenConverter converter = smartToken.owner(); details.converter = address(converter); details.tokens = new TokenWithRatio[](converter.connectorTokenCount()); for (uint256 i = 0; i < details.tokens.length; i++) { details.tokens[i].token = converter.connectorTokens(i); details.tokens[i].ratio = _getReserveRatio(converter, details.tokens[i].token); details.totalRatio = details.totalRatio.add(details.tokens[i].ratio); } } function _getReserveRatio( ISmartTokenConverter converter, IERC20 token ) internal view returns (uint256) { (bool success, bytes memory data) = address(converter).staticcall.gas(10000)( abi.encodeWithSelector( converter.getReserveRatio.selector, token ) ); if (!success) { (, uint32 ratio, , ,) = converter.connectors(address(token)); return uint256(ratio); } return abi.decode(data, (uint256)); } function _canonicalSUSD(IERC20 token) internal pure returns(IERC20) { return token == acientSUSD ? susd : token; } } contract OneSplitSmartTokenView is OneSplitViewWrapBase, OneSplitSmartTokenBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256, uint256[] memory ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_SMART_TOKEN)) { bool isSmartTokenFrom = smartTokenRegistry.isSmartToken(fromToken); bool isSmartTokenTo = smartTokenRegistry.isSmartToken(toToken); if (isSmartTokenFrom && isSmartTokenTo) { ( uint256 returnBntAmount, uint256[] memory smartTokenFromDistribution ) = _getExpectedReturnFromSmartToken( fromToken, bntToken, amount, parts, FLAG_DISABLE_SMART_TOKEN ); ( uint256 returnSmartTokenToAmount, uint256[] memory smartTokenToDistribution ) = _getExpectedReturnToSmartToken( bntToken, toToken, returnBntAmount, parts, FLAG_DISABLE_SMART_TOKEN ); for (uint i = 0; i < smartTokenToDistribution.length; i++) { smartTokenFromDistribution[i] |= smartTokenToDistribution[i] << 128; } return (returnSmartTokenToAmount, smartTokenFromDistribution); } if (isSmartTokenFrom) { return _getExpectedReturnFromSmartToken( fromToken, toToken, amount, parts, FLAG_DISABLE_SMART_TOKEN ); } if (isSmartTokenTo) { return _getExpectedReturnToSmartToken( fromToken, toToken, amount, parts, FLAG_DISABLE_SMART_TOKEN ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFromSmartToken( IERC20 smartToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); SmartTokenDetails memory details = _getSmartTokenDetails(ISmartToken(address(smartToken))); for (uint i = 0; i < details.tokens.length; i++) { uint256 srcAmount = smartTokenFormula.calculateLiquidateReturn( smartToken.totalSupply(), _canonicalSUSD(details.tokens[i].token).balanceOf(details.converter), uint32(details.totalRatio), amount ); if (details.tokens[i].token == toToken) { returnAmount = returnAmount.add(srcAmount); continue; } (uint256 ret, uint256[] memory dist) = this.getExpectedReturn( _canonicalSUSD(details.tokens[i].token), toToken, srcAmount, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } return (returnAmount, distribution); } function _getExpectedReturnToSmartToken( IERC20 fromToken, IERC20 smartToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 minFundAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); minFundAmount = uint256(-1); SmartTokenDetails memory details = _getSmartTokenDetails(ISmartToken(address(smartToken))); uint256[] memory tokenAmounts = new uint256[](details.tokens.length); uint256[] memory dist; uint256[] memory fundAmounts = new uint256[](details.tokens.length); for (uint i = 0; i < details.tokens.length; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].ratio) .div(details.totalRatio); if (details.tokens[i].token != fromToken) { (tokenAmounts[i], dist) = this.getExpectedReturn( fromToken, _canonicalSUSD(details.tokens[i].token), exchangeAmount, parts, flags ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } else { tokenAmounts[i] = exchangeAmount; } fundAmounts[i] = smartTokenFormula.calculatePurchaseReturn( smartToken.totalSupply(), _canonicalSUSD(details.tokens[i].token).balanceOf(details.converter), uint32(details.totalRatio), tokenAmounts[i] ); if (fundAmounts[i] < minFundAmount) { minFundAmount = fundAmounts[i]; } } return (minFundAmount, distribution); } } contract OneSplitSmartToken is OneSplitBaseWrap, OneSplitSmartTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_SMART_TOKEN)) { bool isSmartTokenFrom = smartTokenRegistry.isSmartToken(fromToken); bool isSmartTokenTo = smartTokenRegistry.isSmartToken(toToken); if (isSmartTokenFrom && isSmartTokenTo) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & ((1 << 128) - 1); } uint256 bntBalanceBefore = bntToken.balanceOf(address(this)); _swapFromSmartToken( fromToken, bntToken, amount, dist, FLAG_DISABLE_SMART_TOKEN ); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] >> 128; } uint256 bntBalanceAfter = bntToken.balanceOf(address(this)); return _swapToSmartToken( bntToken, toToken, bntBalanceAfter.sub(bntBalanceBefore), dist, FLAG_DISABLE_SMART_TOKEN ); } if (isSmartTokenFrom) { return _swapFromSmartToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_SMART_TOKEN ); } if (isSmartTokenTo) { return _swapToSmartToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_SMART_TOKEN ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromSmartToken( IERC20 smartToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { SmartTokenDetails memory details = _getSmartTokenDetails(ISmartToken(address(smartToken))); ISmartTokenConverter(details.converter).liquidate(amount); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < details.tokens.length; i++) { if (details.tokens[i].token == toToken) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( _canonicalSUSD(details.tokens[i].token), toToken, _canonicalSUSD(details.tokens[i].token).balanceOf(address(this)), 0, dist, flags ); } } function _swapToSmartToken( IERC20 fromToken, IERC20 smartToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { uint256[] memory dist = new uint256[](distribution.length); uint256 minFundAmount = uint256(-1); SmartTokenDetails memory details = _getSmartTokenDetails(ISmartToken(address(smartToken))); uint256 curFundAmount; for (uint i = 0; i < details.tokens.length; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].ratio) .div(details.totalRatio); if (details.tokens[i].token != fromToken) { uint256 tokenBalanceBefore = _canonicalSUSD(details.tokens[i].token).balanceOf(address(this)); for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( fromToken, _canonicalSUSD(details.tokens[i].token), exchangeAmount, 0, dist, flags ); uint256 tokenBalanceAfter = _canonicalSUSD(details.tokens[i].token).balanceOf(address(this)); curFundAmount = smartTokenFormula.calculatePurchaseReturn( smartToken.totalSupply(), _canonicalSUSD(details.tokens[i].token).balanceOf(details.converter), uint32(details.totalRatio), tokenBalanceAfter.sub(tokenBalanceBefore) ); } else { curFundAmount = smartTokenFormula.calculatePurchaseReturn( smartToken.totalSupply(), _canonicalSUSD(details.tokens[i].token).balanceOf(details.converter), uint32(details.totalRatio), exchangeAmount ); } if (curFundAmount < minFundAmount) { minFundAmount = curFundAmount; } _infiniteApproveIfNeeded(_canonicalSUSD(details.tokens[i].token), details.converter); } ISmartTokenConverter(details.converter).fund(minFundAmount); for (uint i = 0; i < details.tokens.length; i++) { IERC20 reserveToken = _canonicalSUSD(details.tokens[i].token); reserveToken.universalTransfer( msg.sender, reserveToken.universalBalanceOf(address(this)) ); } } } // File: contracts/interface/IUniswapV2Router.sol pragma solidity ^0.5.0; interface IUniswapV2Router { function addLiquidity( IERC20 tokenA, IERC20 tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint256[2] memory amounts, uint liquidity); function removeLiquidity( IERC20 tokenA, IERC20 tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint256[2] memory); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, IERC20[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function getAmountsOut(uint amountIn, IERC20[] calldata path) external view returns (uint[] memory amounts); } // File: contracts/interface/IUniswapV2Pair.sol pragma solidity ^0.5.0; interface IUniswapV2Pair { function factory() external view returns (address); function token0() external view returns (IERC20); function token1() external view returns (IERC20); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); } // File: contracts/OneSplitUniswapV2PoolToken.sol pragma solidity ^0.5.0; library Math { function min(uint x, uint y) internal pure returns (uint z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } contract OneSplitUniswapV2PoolTokenBase { using SafeMath for uint256; IUniswapV2Router constant uniswapRouter = IUniswapV2Router(0xf164fC0Ec4E93095b804a4795bBe1e041497b92a); function isLiquidityPool(IERC20 token) internal view returns (bool) { (bool success, bytes memory data) = address(token).staticcall.gas(2000)( abi.encode(IUniswapV2Pair(address(token)).factory.selector) ); if (!success || data.length == 0) { return false; } return abi.decode(data, (address)) == 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; } struct TokenInfo { IERC20 token; uint256 reserve; } struct PoolDetails { TokenInfo[2] tokens; uint256 totalSupply; } function _getPoolDetails(IUniswapV2Pair pair) internal view returns (PoolDetails memory details) { (uint112 reserve0, uint112 reserve1, ) = pair.getReserves(); details.tokens[0] = TokenInfo({ token: pair.token0(), reserve: reserve0 }); details.tokens[1] = TokenInfo({ token: pair.token1(), reserve: reserve1 }); details.totalSupply = IERC20(address(pair)).totalSupply(); } function _calcRebalanceAmount( uint256 leftover, uint256 balanceOfLeftoverAsset, uint256 secondAssetBalance ) internal pure returns (uint256) { return Math.sqrt( 3988000 * leftover * balanceOfLeftoverAsset + 3988009 * balanceOfLeftoverAsset * balanceOfLeftoverAsset - 9 * balanceOfLeftoverAsset * balanceOfLeftoverAsset / (secondAssetBalance - 1) ) / 1994 - balanceOfLeftoverAsset * 1997 / 1994; } } contract OneSplitUniswapV2PoolTokenView is OneSplitViewWrapBase, OneSplitUniswapV2PoolTokenBase { function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN)) { bool isPoolTokenFrom = isLiquidityPool(fromToken); bool isPoolTokenTo = isLiquidityPool(toToken); if (isPoolTokenFrom && isPoolTokenTo) { ( uint256 returnWETHAmount, uint256[] memory poolTokenFromDistribution ) = _getExpectedReturnFromUniswapV2PoolToken( fromToken, weth, amount, parts, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); ( uint256 returnPoolTokenToAmount, uint256[] memory poolTokenToDistribution ) = _getExpectedReturnToUniswapV2PoolToken( weth, toToken, returnWETHAmount, parts, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); for (uint i = 0; i < poolTokenToDistribution.length; i++) { poolTokenFromDistribution[i] |= poolTokenToDistribution[i] << 128; } return (returnPoolTokenToAmount, poolTokenFromDistribution); } if (isPoolTokenFrom) { return _getExpectedReturnFromUniswapV2PoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); } if (isPoolTokenTo) { return _getExpectedReturnToUniswapV2PoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); } } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFromUniswapV2PoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); PoolDetails memory details = _getPoolDetails(IUniswapV2Pair(address(poolToken))); for (uint i = 0; i < 2; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].reserve) .div(details.totalSupply); if (toToken == details.tokens[i].token) { returnAmount = returnAmount.add(exchangeAmount); continue; } (uint256 ret, uint256[] memory dist) = this.getExpectedReturn( details.tokens[i].token, toToken, exchangeAmount, parts, flags ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } return (returnAmount, distribution); } function _getExpectedReturnToUniswapV2PoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); PoolDetails memory details = _getPoolDetails(IUniswapV2Pair(address(poolToken))); // will overwritten to liquidity amounts uint256[2] memory amounts; amounts[0] = amount.div(2); amounts[1] = amount.sub(amounts[0]); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { if (fromToken == details.tokens[i].token) { continue; } (amounts[i], dist) = this.getExpectedReturn( fromToken, details.tokens[i].token, amounts[i], parts, flags ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } uint256 possibleLiquidity0 = amounts[0].mul(details.totalSupply).div(details.tokens[0].reserve); returnAmount = Math.min( possibleLiquidity0, amounts[1].mul(details.totalSupply).div(details.tokens[1].reserve) ); uint256 leftoverIndex = possibleLiquidity0 > returnAmount ? 0 : 1; IERC20[] memory path = new IERC20[](2); path[0] = details.tokens[leftoverIndex].token; path[1] = details.tokens[1 - leftoverIndex].token; uint256 optimalAmount = amounts[1 - leftoverIndex].mul( details.tokens[leftoverIndex].reserve ).div(details.tokens[1 - leftoverIndex].reserve); IERC20 _poolToken = poolToken; // stack too deep uint256 exchangeAmount = _calcRebalanceAmount( amounts[leftoverIndex].sub(optimalAmount), path[0].balanceOf(address(_poolToken)).add(optimalAmount), path[1].balanceOf(address(_poolToken)).add(amounts[1 - leftoverIndex]) ); (bool success, bytes memory data) = address(uniswapRouter).staticcall.gas(200000)( abi.encodeWithSelector( uniswapRouter.getAmountsOut.selector, exchangeAmount, path ) ); if (!success) { return ( returnAmount, distribution ); } uint256[] memory amountsOutAfterSwap = abi.decode(data, (uint256[])); uint256 _addedLiquidity = returnAmount; // stack too deep PoolDetails memory _details = details; // stack too deep returnAmount = _addedLiquidity.add( amountsOutAfterSwap[1] // amountOut after swap .mul(_details.totalSupply.add(_addedLiquidity)) .div(_details.tokens[1 - leftoverIndex].reserve.sub(amountsOutAfterSwap[1])) ); return ( returnAmount, distribution ); } } contract OneSplitUniswapV2PoolToken is OneSplitBaseWrap, OneSplitUniswapV2PoolTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == toToken) { return; } if (!flags.check(FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN)) { bool isPoolTokenFrom = isLiquidityPool(fromToken); bool isPoolTokenTo = isLiquidityPool(toToken); if (isPoolTokenFrom && isPoolTokenTo) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & ((1 << 128) - 1); } uint256 wEthBalanceBefore = weth.balanceOf(address(this)); _swapFromUniswapV2PoolToken( fromToken, weth, amount, dist, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] >> 128; } uint256 wEthBalanceAfter = weth.balanceOf(address(this)); return _swapToUniswapV2PoolToken( weth, toToken, wEthBalanceAfter.sub(wEthBalanceBefore), dist, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); } if (isPoolTokenFrom) { return _swapFromUniswapV2PoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); } if (isPoolTokenTo) { return _swapToUniswapV2PoolToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromUniswapV2PoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { _infiniteApproveIfNeeded(poolToken, address(uniswapRouter)); IERC20 [2] memory tokens = [ IUniswapV2Pair(address(poolToken)).token0(), IUniswapV2Pair(address(poolToken)).token1() ]; uint256[2] memory amounts = uniswapRouter.removeLiquidity( tokens[0], tokens[1], amount, uint256(0), uint256(0), address(this), now.add(1800) ); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { if (toToken == tokens[i]) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( tokens[i], toToken, amounts[i], 0, dist, flags ); } } function _swapToUniswapV2PoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { IERC20 [2] memory tokens = [ IUniswapV2Pair(address(poolToken)).token0(), IUniswapV2Pair(address(poolToken)).token1() ]; // will overwritten to liquidity amounts uint256[2] memory amounts; amounts[0] = amount.div(2); amounts[1] = amount.sub(amounts[0]); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { _infiniteApproveIfNeeded(tokens[i], address(uniswapRouter)); if (fromToken == tokens[i]) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } this.swap( fromToken, tokens[i], amounts[i], 0, dist, flags ); amounts[i] = tokens[i].universalBalanceOf(address(this)); } (uint256[2] memory redeemAmounts, ) = uniswapRouter.addLiquidity( tokens[0], tokens[1], amounts[0], amounts[1], uint256(0), uint256(0), address(this), now.add(1800) ); if ( redeemAmounts[0] == amounts[0] && redeemAmounts[1] == amounts[1] ) { return; } uint256 leftoverIndex = amounts[0] != redeemAmounts[0] ? 0 : 1; IERC20[] memory path = new IERC20[](2); path[0] = tokens[leftoverIndex]; path[1] = tokens[1 - leftoverIndex]; address _poolToken = address(poolToken); // stack too deep uint256 leftover = amounts[leftoverIndex].sub(redeemAmounts[leftoverIndex]); uint256 exchangeAmount = _calcRebalanceAmount( leftover, path[0].balanceOf(_poolToken), path[1].balanceOf(_poolToken) ); (bool success, bytes memory data) = address(uniswapRouter).call.gas(1000000)( abi.encodeWithSelector( uniswapRouter.swapExactTokensForTokens.selector, exchangeAmount, uint256(0), path, address(this), now.add(1800) ) ); if (!success) { return; } uint256[] memory amountsOut = abi.decode(data, (uint256[])); address(uniswapRouter).call.gas(1000000)( abi.encodeWithSelector( uniswapRouter.addLiquidity.selector, tokens[0], tokens[1], leftoverIndex == 0 ? leftover.sub(amountsOut[0]) : amountsOut[1], leftoverIndex == 1 ? leftover.sub(amountsOut[0]) : amountsOut[1], uint256(0), uint256(0), address(this), now.add(1800) ) ); } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMultiPathView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, //OneSplitBalancerPoolTokenView, //OneSplitUniswapPoolTokenView, //OneSplitCurvePoolTokenView //OneSplitSmartTokenView, OneSplitUniswapV2PoolTokenView { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplit) public { oneSplitView = _oneSplit; } function getExpectedReturn( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { if (fromToken == toToken) { return (amount, new uint256[](DEXES_COUNT)); } return super.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function _getExpectedReturnFloor( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns( uint256 returnAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } } contract OneSplitWrap is OneSplitBaseWrap, //OneSplitMultiPath, OneSplitChai, OneSplitBdai, OneSplitAave, // OneSplitFulcrum, OneSplitCompound, OneSplitIearn, OneSplitIdle, OneSplitWeth, //OneSplitBalancerPoolToken, //OneSplitUniswapPoolToken, //OneSplitCurvePoolToken //OneSplitSmartToken, OneSplitUniswapV2PoolToken { 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 toToken, uint256 amount, uint256 parts, uint256 flags // 1 - Uniswap, 2 - Kyber, 4 - Bancor, 8 - Oasis, 16 - Compound, 32 - Fulcrum, 64 - Chai, 128 - Aave, 256 - SmartToken, 1024 - bDAI ) public view returns( uint256 /*returnAmount*/, uint256[] memory /*distribution*/ ) { return oneSplitView.getExpectedReturn( fromToken, toToken, amount, parts, flags ); } function swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, // [Uniswap, Kyber, Bancor, Oasis] uint256 flags // 16 - Compound, 32 - Fulcrum, 64 - Chai, 128 - Aave, 256 - SmartToken, 1024 - bDAI ) public payable { if (msg.sender != address(this)) { fromToken.universalTransferFrom(msg.sender, address(this), amount); } _swap(fromToken, toToken, amount, distribution, flags); uint256 returnAmount = toToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); if (msg.sender != address(this)) { toToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } } function _swapFloor( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { (bool success, bytes memory data) = address(oneSplit).delegatecall( abi.encodeWithSelector( this.swap.selector, fromToken, toToken, amount, 0, distribution, flags ) ); assembly { switch success // delegatecall returns 0 on error. case 0 { revert(add(data, 32), returndatasize) } } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IOneSplitView","name":"_oneSplitView","type":"address"},{"internalType":"contract IOneSplit","name":"_oneSplit","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"DEXES_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_AAVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_ALL_SPLIT_SOURCES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_ALL_WRAP_SOURCES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_BALANCER_POOL_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_BANCOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_BDAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CHAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_COMPOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_BINANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_COMPOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_PAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_SYNTHETIX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_USDT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_Y","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_CURVE_ZAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_FULCRUM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_IDLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_IEARN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_KYBER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_MOONISWAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_OASIS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_SMART_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_POOL_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2_ALL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2_DAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2_ETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2_POOL_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_UNISWAP_V2_USDC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_DISABLE_WETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_KYBER_BANCOR_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_KYBER_OASIS_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_KYBER_UNISWAP_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_MULTI_PATH_DAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_MULTI_PATH_ETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_MULTI_PATH_USDC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_UNISWAP_AAVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_UNISWAP_CHAI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FLAG_ENABLE_UNISWAP_COMPOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"_idleSwap","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"_superOneSplitIdleSwap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"aave","outputs":[{"internalType":"contract IAaveLendingPool","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bancorContractRegistry","outputs":[{"internalType":"contract IBancorContractRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bancorConverterRegistry","outputs":[{"internalType":"contract IBancorConverterRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bancorEtherToken","outputs":[{"internalType":"contract IBancorEtherToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bdai","outputs":[{"internalType":"contract IBdai","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bnt","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"btu","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"busd","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cETH","outputs":[{"internalType":"contract ICompoundEther","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"chai","outputs":[{"internalType":"contract IChai","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"compound","outputs":[{"internalType":"contract ICompound","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curveBinance","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curveCompound","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curvePax","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curveSynthetix","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curveUsdt","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"curveY","outputs":[{"internalType":"contract ICurve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dai","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","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":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kyberNetworkProxy","outputs":[{"internalType":"contract IKyberNetworkProxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mooniswapRegistry","outputs":[{"internalType":"contract IMooniswapRegistry","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oasisExchange","outputs":[{"internalType":"contract IOasisExchange","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplit","outputs":[{"internalType":"contract IOneSplit","name":"","type":"address"}],"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":true,"inputs":[],"name":"pax","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"susd","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"toToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"swap","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"tusd","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"uniswapFactory","outputs":[{"internalType":"contract IUniswapFactory","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"uniswapV2","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"usdc","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"usdt","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052600080546001600160a01b0319908116736a4ffaafa8dd400676df8076ad6c724867b0e2e8179091556001805490911673b683d83a532e2cb7dfa5275eed3698436371cc9f17905534801561005857600080fd5b50604051620051d1380380620051d18339818101604052604081101561007d57600080fd5b508051602090910151600280546001600160a01b039384166001600160a01b0319918216179091556003805493909216921691909117905561510c80620000c56000396000f3fe6080604052600436106104525760003560e01c8063819faf7b1161023f578063c925777511610139578063d77366a4116100b6578063f4b9fa751161007a578063f4b9fa7514610cb4578063f56e281f14610cc9578063f69e204614610cde578063fa3f110b14610cf3578063fbe4ed9514610d0857610452565b8063d77366a414610b98578063dc1536b214610bad578063e2a7515e14610bc2578063e355812314610c8a578063e44987b414610c9f57610452565b8063cede5f6a116100fd578063cede5f6a14610abe578063d1ae606314610ad3578063d1aee5e3146105b7578063d393c3e914610b6e578063d70a2d1f14610b8357610452565b8063c925777514610a55578063c989b66714610a6a578063c9b42c6714610a7f578063cc26e9fc14610a94578063ce74b7ac14610aa957610452565b8063a734f06e116101c7578063bf2c5a071161018b578063bf2c5a07146109ec578063c11f4f1114610a01578063c762a46c14610a16578063c77b9de614610a2b578063c7f112e414610a4057610452565b8063a734f06e14610998578063b0a7ef29146109ad578063b184a3ae146109c2578063b3bc784414610857578063b69d0456146109d757610452565b80638ea812c01161020e5780638ea812c014610881578063944a32e214610896578063a1b4d01114610959578063a2878cb11461096e578063a4792ab31461098357610452565b8063819faf7b1461082d578063851954fa146108425780638aea49d2146108575780638bdb2afa1461086c57610452565b8063423d03f9116103505780635ae51b82116102d85780636cbc4a6e1161029c5780636cbc4a6e146107c457806375a8b012146107d957806375b5be2d146107ee5780637a88bdbd146108035780637e09b9c21461081857610452565b80635ae51b821461075b5780635c0cb4791461077057806364ec4e5c1461078557806368e2a0141461079a5780636b5a4ca2146107af57610452565b80634a7101d51161031f5780634a7101d5146106f25780635187c0911461070757806351f1985c1461071c57806352a701b4146107315780635aa8fb481461074657610452565b8063423d03f91461069e57806343ee21f0146106b357806344211d62146106c85780634752c680146106dd57610452565b80632d3b5207116103de5780633ca5b234116103a25780633ca5b2341461064a5780633e413bee1461065f5780633fc8cef31461067457806340ab7b8c146106895780634226a9b9146105e157610452565b80632d3b5207146105e15780632e707bd2146105f65780632f48ab7d1461060b57806334b4dabb14610620578063372a26cb1461063557610452565b8063139891401161042557806313989140146105785780631d209b651461058d5780632113240d146105a257806321a360f5146105b757806322320c98146105cc57610452565b806305d8aa0a14610461578063085e2c5b1461048857806312dea160146105325780631388b42014610563575b3332141561045f57600080fd5b005b34801561046d57600080fd5b50610476610d1d565b60408051918252519081900360200190f35b34801561049457600080fd5b506104d7600480360360a08110156104ab57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060800135610d24565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561051d578181015183820152602001610505565b50505050905001935050505060405180910390f35b34801561053e57600080fd5b50610547610e6c565b604080516001600160a01b039092168252519081900360200190f35b34801561056f57600080fd5b50610547610e84565b34801561058457600080fd5b50610476610e9c565b34801561059957600080fd5b50610476610ea2565b3480156105ae57600080fd5b50610476610eaa565b3480156105c357600080fd5b50610476610eb0565b3480156105d857600080fd5b50610547610eb9565b3480156105ed57600080fd5b50610476610ed1565b34801561060257600080fd5b50610476610ed9565b34801561061757600080fd5b50610547610ede565b34801561062c57600080fd5b50610476610ef6565b34801561064157600080fd5b50610547610efb565b34801561065657600080fd5b50610547610f13565b34801561066b57600080fd5b50610547610f2b565b34801561068057600080fd5b50610547610f43565b34801561069557600080fd5b50610547610f5b565b3480156106aa57600080fd5b50610547610f73565b3480156106bf57600080fd5b50610547610f8b565b3480156106d457600080fd5b50610476610f9a565b3480156106e957600080fd5b50610476610f9f565b3480156106fe57600080fd5b50610476610fa7565b34801561071357600080fd5b50610547610fac565b34801561072857600080fd5b50610547610fc4565b34801561073d57600080fd5b50610547610fdc565b34801561075257600080fd5b50610476610ff4565b34801561076757600080fd5b50610476610ffa565b34801561077c57600080fd5b50610476611000565b34801561079157600080fd5b50610476611005565b3480156107a657600080fd5b5061047661100c565b3480156107bb57600080fd5b50610547611013565b3480156107d057600080fd5b50610476611022565b3480156107e557600080fd5b50610476611029565b3480156107fa57600080fd5b5061054761102f565b34801561080f57600080fd5b50610476611042565b34801561082457600080fd5b50610476611047565b34801561083957600080fd5b5061054761104e565b34801561084e57600080fd5b50610547611066565b34801561086357600080fd5b5061047661107e565b34801561087857600080fd5b50610547611087565b34801561088d57600080fd5b5061047661109f565b61045f600480360360a08110156108ac57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156108e657600080fd5b8201836020820111156108f857600080fd5b803590602001918460208302840111600160201b8311171561091957600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955050913592506110a8915050565b34801561096557600080fd5b506105476114e4565b34801561097a57600080fd5b506104766114fc565b34801561098f57600080fd5b50610547611504565b3480156109a457600080fd5b5061054761151c565b3480156109b957600080fd5b50610476611534565b3480156109ce57600080fd5b5061054761153a565b3480156109e357600080fd5b50610547611552565b3480156109f857600080fd5b5061047661156a565b348015610a0d57600080fd5b50610547611572565b348015610a2257600080fd5b50610476611581565b348015610a3757600080fd5b50610476611586565b348015610a4c57600080fd5b5061047661158c565b348015610a6157600080fd5b50610547611594565b348015610a7657600080fd5b506104766115ac565b348015610a8b57600080fd5b506104766115b3565b348015610aa057600080fd5b506104766115ba565b348015610ab557600080fd5b506104766115bf565b348015610aca57600080fd5b506105476115c7565b348015610adf57600080fd5b5061045f600480360360a0811015610af657600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610b3057600080fd5b820183602082011115610b4257600080fd5b803590602001918460208302840111600160201b83111715610b6357600080fd5b9193509150356115df565b348015610b7a57600080fd5b5061047661162c565b348015610b8f57600080fd5b50610547611633565b348015610ba457600080fd5b5061054761164b565b348015610bb957600080fd5b50610476611663565b61045f600480360360c0811015610bd857600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b811115610c1757600080fd5b820183602082011115610c2957600080fd5b803590602001918460208302840111600160201b83111715610c4a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250611669915050565b348015610c9657600080fd5b50610476611755565b348015610cab57600080fd5b5061047661175d565b348015610cc057600080fd5b50610547611765565b348015610cd557600080fd5b5061047661177d565b348015610cea57600080fd5b50610547611782565b348015610cff57600080fd5b5061047661179a565b348015610d1457600080fd5b506105476117a2565b6220000081565b6002546040805163085e2c5b60e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052608482018590529151600093606093169163085e2c5b9160a48083019287929190829003018186803b158015610d9057600080fd5b505afa158015610da4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015610dcd57600080fd5b815160208301805160405192949293830192919084600160201b821115610df357600080fd5b908301906020820185811115610e0857600080fd5b82518660208202830111600160201b82111715610e2457600080fd5b82525081516020918201928201910280838360005b83811015610e51578181015183820152602001610e39565b50505050905001604052505050915091509550959350505050565b7352ae12abe5d8bd778bd5397f99ca900624cfadd481565b73794e6e91555438afc3ccf1c5076a74f42133d08d81565b61200081565b630400000081565b61800081565b64020000000081565b73a5407eae9ba41422680e2e00537571bcc53efbfd81565b600160201b81565b608081565b73dac17f958d2ee523a2206206994597c13d831ec781565b604081565b7379a8c46dea5ada233abaffd40f3a0a2b1e5a4f2781565b734fabb145d64652a948d72533023f6e7a623c7c5381565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b731f573d6fb3f13d689ff844b4ce37794d79a7ff1c81565b7345f783cce6b7ff23b2ab2d70e416cdb7d6055f5181565b6003546001600160a01b031681565b601081565b631e00000081565b602081565b735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b73a2b47e3d5c44877cca798226b7b8118f9bfb7a5681565b738e870d67f660d95d5be530380d0ec0bd388289e181565b61400081565b61080081565b600881565b6202000081565b6210000081565b6001546001600160a01b031681565b6208000081565b61040081565b6e085d4780b73119b644ae5ecd22b37681565b600281565b6240000081565b73398ec7346dcd622edc5ae82352f02be94c62d11981565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce31581565b64040000000081565b73c0a47dfe034b400b47bdad5fecda2621de6c4d9581565b64080000000081565b6110b0614fda565b6110b86117b1565b905060005b600281101561128b578181600281106110d257fe5b60200201516001600160a01b0316876001600160a01b031614156112835760008282600281106110fe57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561113b57600080fd5b505afa15801561114f573d6000803e3d6000fd5b505050506040513d602081101561116557600080fd5b50519050600083836002811061117757fe5b60200201516001600160a01b031663c85c93aa88600160006040519080825280602002602001820160405280156111b8578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015611218578181015183820152602001611200565b50505050905001945050505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b5051905061127a82898389896110a8565b505050506114dd565b6001016110bd565b5060005b60028110156114cd578181600281106112a457fe5b60200201516001600160a01b0316866001600160a01b031614156114c55760008282600281106112d057fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561130d57600080fd5b505afa158015611321573d6000803e3d6000fd5b505050506040513d602081101561133757600080fd5b5051905061134888828888886117f8565b6113628184846002811061135857fe5b6020020151611805565b82826002811061136e57fe5b60200201516001600160a01b0316633cfcef64826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156113d757600080fd5b505afa1580156113eb573d6000803e3d6000fd5b505050506040513d602081101561140157600080fd5b50516040805160008082526020820190925290506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561146a578181015183820152602001611452565b505050509050019350505050602060405180830381600087803b15801561149057600080fd5b505af11580156114a4573d6000803e3d6000fd5b505050506040513d60208110156114ba57600080fd5b506114dd9350505050565b60010161128f565b506114db86868686866117f8565b505b5050505050565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b634000000081565b737079e8517594e5b21d2b9a0d17cb33f5fe2bca7081565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b61100081565b7306364f10b501e868329afbc005b3492902d6c76381565b7306af07097c9eeb7fd685c692751d5c66db49c21581565b630800000081565b6000546001600160a01b031681565b600181565b61020081565b638000000081565b7357ab1ec28d129707052df4df418d58a2d46d5f5181565b6280000081565b6204000081565b601281565b630200000081565b7352ea46506b9cc5ef470c5bf89f17dc28bb35d85c81565b3330146115eb57600080fd5b6114db8686868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892506117f8915050565b6201000081565b73f6e2d7f616b67e46d708e4410746e9aab3a4c51881565b73818e6fecd516ecc3849daf6845e3ec868087b75581565b61010081565b33301461168b5761168b6001600160a01b03871633308763ffffffff6118be16565b61169886868685856119dd565b60006116b36001600160a01b0387163063ffffffff611cb616565b9050838110156116f45760405162461bcd60e51b81526004018080602001828103825260358152602001806150186035913960400191505060405180910390fd5b33301461174c576117156001600160a01b038716338363ffffffff611d6216565b5061174a336117336001600160a01b038a163063ffffffff611cb616565b6001600160a01b038a16919063ffffffff611d6216565b505b50505050505050565b631000000081565b632000000081565b736b175474e89094c44da98b954eedeac495271d0f81565b600481565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b630100000081565b6002546001600160a01b031681565b6117b9614fda565b50604080518082019091527310ec0d497824e342bcb0edce00959142aaa766dd815273eb66acc3d011056b00ea521f8203580c2e5d3991602082015290565b6114dd8585858585611de0565b611817826001600160a01b03166121c5565b6118ba5760408051636eb1769f60e11b81523060048201526001600160a01b038381166024830152915160ff9285169163dd62ed3e916044808301926020929190829003018186803b15801561186c57600080fd5b505afa158015611880573d6000803e3d6000fd5b505050506040513d602081101561189657600080fd5b5051901c6118ba576118ba6001600160a01b0383168260001963ffffffff61220116565b5050565b806118c8576119d7565b6118d1846121c5565b156119bc576001600160a01b038316331480156118ee5750803410155b6119295760405162461bcd60e51b815260040180806020018281038252602b81526020018061504d602b913960400191505060405180910390fd5b6001600160a01b0382163014611971576040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561196f573d6000803e3d6000fd5b505b803411156119b757336108fc61198d348463ffffffff6122d716565b6040518115909202916000818181858888f193505050501580156119b5573d6000803e3d6000fd5b505b6119d7565b6119d76001600160a01b03851684848463ffffffff61231916565b50505050565b836001600160a01b0316856001600160a01b031614156119fc576114dd565b611a118164080000000063ffffffff61237316565b611ca9576000611a2086612379565b90506000611a2d86612379565b9050818015611a395750805b15611c6f5760608451604051908082528060200260200182016040528015611a6b578160200160208202803883390190505b50905060005b8551811015611abf57858181518110611a8657fe5b60200260200101516fffffffffffffffffffffffffffffffff16828281518110611aac57fe5b6020908102919091010152600101611a71565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b158015611b1557600080fd5b505afa158015611b29573d6000803e3d6000fd5b505050506040513d6020811015611b3f57600080fd5b50519050611b698973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc289856408000000006124a6565b60005b8651811015611bac576080878281518110611b8357fe5b6020026020010151901c838281518110611b9957fe5b6020908102919091010152600101611b6c565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b158015611c0257600080fd5b505afa158015611c16573d6000803e3d6000fd5b505050506040513d6020811015611c2c57600080fd5b50519050611c6573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a611c59848663ffffffff6122d716565b86640800000000612873565b50505050506114dd565b8115611c8e57611c87878787876408000000006124a6565b50506114dd565b8015611ca657611c8787878787640800000000612873565b50505b6114dd8585858585613376565b6000611cc1836121c5565b15611cd757506001600160a01b03811631611d5c565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611d2d57600080fd5b505afa158015611d41573d6000803e3d6000fd5b505050506040513d6020811015611d5757600080fd5b505190505b92915050565b600081611d7157506001611dd9565b611d7a846121c5565b15611dbb576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611db5573d6000803e3d6000fd5b50611dd9565b611dd56001600160a01b038516848463ffffffff61338316565b5060015b9392505050565b836001600160a01b0316856001600160a01b03161415611dff576114dd565b611e07614ff8565b611e0f6133d5565b9050611e238261080063ffffffff61237316565b6121b85760005b600d811015611fe2578181600d8110611e3f57fe5b60200201516001600160a01b0316876001600160a01b03161415611fda5760008282600d8110611e6b57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea857600080fd5b505afa158015611ebc573d6000803e3d6000fd5b505050506040513d6020811015611ed257600080fd5b505190508282600d8110611ee257fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611f2c57600080fd5b505af1158015611f40573d6000803e3d6000fd5b50505050611fd28188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611f9f57600080fd5b505afa158015611fb3573d6000803e3d6000fd5b505050506040513d6020811015611fc957600080fd5b50518888611de0565b5050506114dd565b600101611e2a565b5060005b600d8110156121b6578181600d8110611ffb57fe5b60200201516001600160a01b0316866001600160a01b031614156121ae5760008282600d811061202757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561206457600080fd5b505afa158015612078573d6000803e3d6000fd5b505050506040513d602081101561208e57600080fd5b5051905061209f8882888888613542565b6120af818484600d811061135857fe5b8282600d81106120bb57fe5b60200201516001600160a01b031663b6b55f25826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561212457600080fd5b505afa158015612138573d6000803e3d6000fd5b505050506040513d602081101561214e57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561218e57600080fd5b505af11580156121a2573d6000803e3d6000fd5b505050505050506114dd565b600101611fe6565b505b6114db8686868686613542565b60006001600160a01b03821615806121f957506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b61220a836121c5565b6122d257600081118015612298575060408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561226a57600080fd5b505afa15801561227e573d6000803e3d6000fd5b505050506040513d602081101561229457600080fd5b5051115b156122b8576122b86001600160a01b03841683600063ffffffff61354f16565b6122d26001600160a01b038416838363ffffffff61354f16565b505050565b6000611dd983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613662565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526119d79085906136f9565b16151590565b6040805163c45a015560e01b60208083019190915282518083038201815291830192839052815160009384936060936001600160a01b038816936107d093918291908401908083835b602083106123e15780518252601f1990920191602091820191016123c2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114612442576040519150601f19603f3d011682016040523d82523d6000602084013e612447565b606091505b509150915081158061245857508051155b15612468576000925050506121fc565b80806020019051602081101561247d57600080fd5b50516001600160a01b0316735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f14949350505050565b6124c48573f164fc0ec4e93095b804a4795bbe1e041497b92a611805565b6124cc614fda565b6040518060400160405280876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561251057600080fd5b505afa158015612524573d6000803e3d6000fd5b505050506040513d602081101561253a57600080fd5b50516001600160a01b0390811682526040805163d21220a760e01b81529051602093840193928b169263d21220a79260048082019391829003018186803b15801561258457600080fd5b505afa158015612598573d6000803e3d6000fd5b505050506040513d60208110156125ae57600080fd5b50516001600160a01b0316905290506125c5614fda565b8151602083015173f164fc0ec4e93095b804a4795bbe1e041497b92a9163baa2abde9188600080306125f9426107086138b1565b604080516001600160e01b031960e08b901b1681526001600160a01b039889166004820152968816602488015260448701959095526064860193909352608485019190915290931660a483015260c4820192909252815160e480830193928290030181600087803b15801561266d57600080fd5b505af1158015612681573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060408110156126a657600080fd5b5084516040805182815260208084028201019091529192506060919080156126d8578160200160208202803883390190505b50905060005b6002811015612868578381600281106126f357fe5b60200201516001600160a01b0316886001600160a01b0316141561271657612860565b60005b865181101561275e578160080287828151811061273257fe5b6020026020010151901c60ff1683828151811061274b57fe5b6020908102919091010152600101612719565b503063e2a7515e85836002811061277157fe5b60200201518a86856002811061278357fe5b60200201516000878b6040518763ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561281d578181015183820152602001612805565b50505050905001975050505050505050600060405180830381600087803b15801561284757600080fd5b505af115801561285b573d6000803e3d6000fd5b505050505b6001016126de565b505050505050505050565b61287b614fda565b6040518060400160405280866001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b1580156128bf57600080fd5b505afa1580156128d3573d6000803e3d6000fd5b505050506040513d60208110156128e957600080fd5b50516001600160a01b0390811682526040805163d21220a760e01b81529051602093840193928a169263d21220a79260048082019391829003018186803b15801561293357600080fd5b505afa158015612947573d6000803e3d6000fd5b505050506040513d602081101561295d57600080fd5b50516001600160a01b031690529050612974614fda565b61298585600263ffffffff61390b16565b8082526129939086906122d7565b816001602002018181525050606084516040519080825280602002602001820160405280156129cc578160200160208202803883390190505b50905060005b6002811015612bc557612a098482600281106129ea57fe5b602002015173f164fc0ec4e93095b804a4795bbe1e041497b92a611805565b838160028110612a1557fe5b60200201516001600160a01b0316896001600160a01b03161415612a3857612bbd565b60005b8651811015612a805781600802878281518110612a5457fe5b6020026020010151901c60ff16838281518110612a6d57fe5b6020908102919091010152600101612a3b565b503063e2a7515e8a868460028110612a9457fe5b6020020151868560028110612aa557fe5b60200201516000878b6040518763ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015612b3f578181015183820152602001612b27565b50505050905001975050505050505050600060405180830381600087803b158015612b6957600080fd5b505af1158015612b7d573d6000803e3d6000fd5b50505050612bab30858360028110612b9157fe5b60200201516001600160a01b03169063ffffffff611cb616565b838260028110612bb757fe5b60200201525b6001016129d2565b50612bce614fda565b835160208086015185519186015173f164fc0ec4e93095b804a4795bbe1e041497b92a9363e8e337009390929160008030612c0b426107086138b1565b6040518963ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001886001600160a01b03166001600160a01b03168152602001878152602001868152602001858152602001848152602001836001600160a01b03166001600160a01b0316815260200182815260200198505050505050505050606060405180830381600087803b158015612ca857600080fd5b505af1158015612cbc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506060811015612ce157600080fd5b5083518151919250148015612cfd575060208084015190820151145b15612d0b57505050506114dd565b805183516000911415612d1f576001612d22565b60005b6040805160028082526060808301845260ff9490941694509091602083019080388339019050509050858260028110612d5757fe5b602002015181600081518110612d6957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050858260010360028110612d9857fe5b602002015181600181518110612daa57fe5b6001600160a01b0390921660209283029190910190910152896000612df6858560028110612dd457fe5b6020020151888660028110612de557fe5b60200201519063ffffffff6122d716565b90506000612f318285600081518110612e0b57fe5b60200260200101516001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e6857600080fd5b505afa158015612e7c573d6000803e3d6000fd5b505050506040513d6020811015612e9257600080fd5b5051865187906001908110612ea357fe5b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612f0057600080fd5b505afa158015612f14573d6000803e3d6000fd5b505050506040513d6020811015612f2a57600080fd5b505161394d565b90506000606073f164fc0ec4e93095b804a4795bbe1e041497b92a620f42406338ed173960e01b85858a30612f6e4261070863ffffffff6138b116565b6040516024018086815260200185815260200180602001846001600160a01b03166001600160a01b03168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015612fdb578181015183820152602001612fc3565b505050509050019650505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518082805190602001908083835b6020831061304c5780518252601f19909201916020918201910161302d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d80600081146130af576040519150601f19603f3d011682016040523d82523d6000602084013e6130b4565b606091505b5091509150816130ce5750505050505050505050506114dd565b60608180602001905160208110156130e557600080fd5b8101908080516040519392919084600160201b82111561310457600080fd5b90830190602082018581111561311957600080fd5b82518660208202830111600160201b8211171561313557600080fd5b82525081516020918201928201910280838360005b8381101561316257818101518382015260200161314a565b50505050919091016040525092935073f164fc0ec4e93095b804a4795bbe1e041497b92a9250620f4240915062e8e33760e81b90508e600060200201518f600160200201518c156131c757856001815181106131ba57fe5b60200260200101516131ee565b6131ee866000815181106131d757fe5b60200260200101518b6122d790919063ffffffff16565b8d600114613210578660018151811061320357fe5b6020026020010151613237565b6132378760008151811061322057fe5b60200260200101518c6122d790919063ffffffff16565b6000803061324d4261070863ffffffff6138b116565b604080516001600160a01b03998a16602482015297891660448901526064880196909652608487019490945260a486019290925260c485015290931660e4830152610104808301939093528051808303909301835261012490910181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106132f85780518252601f1990920191602091820191016132d9565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d806000811461335b576040519150601f19603f3d011682016040523d82523d6000602084013e613360565b606091505b5050505050505050505050505050505050505050565b6114dd8585858585613998565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526122d29084906136f9565b6133dd614ff8565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b6114dd8585858585613cd1565b8015806135d5575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156135a757600080fd5b505afa1580156135bb573d6000803e3d6000fd5b505050506040513d60208110156135d157600080fd5b5051155b6136105760405162461bcd60e51b81526004018080602001828103825260368152602001806150a26036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526122d29084906136f9565b600081848411156136f15760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156136b657818101518382015260200161369e565b50505050905090810190601f1680156136e35780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b61370b826001600160a01b0316613f11565b61375c576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b6020831061379a5780518252601f19909201916020918201910161377b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146137fc576040519150601f19603f3d011682016040523d82523d6000602084013e613801565b606091505b509150915081613858576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156119d75780806020019051602081101561387457600080fd5b50516119d75760405162461bcd60e51b815260040180806020018281038252602a815260200180615078602a913960400191505060405180910390fd5b600082820183811015611dd9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611dd983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613f4d565b60006107ca6107cd8402046107ca613987600185038687600902028161396f57fe5b048687623cda2902028789623cda2002020103613fb2565b8161398e57fe5b0403949350505050565b836001600160a01b0316856001600160a01b031614156139b7576114dd565b6139ca816208000063ffffffff61237316565b613cc4576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613af457604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613a4c57600080fd5b505afa158015613a60573d6000803e3d6000fd5b505050506040513d6020811015613a7657600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015613ab657600080fd5b505af1158015613aca573d6000803e3d6000fd5b50505050613aef73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585614003565b6114dd565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415613b7257604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613a4c57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613c2557613bb88573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585613998565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0306001600160a01b0316316040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1157600080fd5b505af1158015611c65573d6000803e3d6000fd5b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415613cc457613c6b8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585613998565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0306001600160a01b0316316040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1157600080fd5b6114dd8585858585614003565b836001600160a01b0316856001600160a01b03161415613cf0576114dd565b613d0181601063ffffffff61237316565b613f04576000613d1086614010565b90506001600160a01b0380821614613dbf57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613d6857600080fd5b505af1158015613d7c573d6000803e3d6000fd5b505050506040513d6020811015613d9257600080fd5b5060009050613db06001600160a01b0383163063ffffffff611cb616565b9050611c878287838787613cd1565b613dc885614010565b90506001600160a01b0380821614613f0257613de78682868686614208565b6000613e026001600160a01b0383163063ffffffff611cb616565b9050613e16826001600160a01b03166121c5565b15613e8857734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e6a57600080fd5b505af1158015613e7e573d6000803e3d6000fd5b5050505050611c87565b613e928287611805565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613ed857600080fd5b505af1158015613eec573d6000803e3d6000fd5b505050506040513d602081101561127a57600080fd5b505b6114dd8585858585614208565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613f4557508115155b949350505050565b60008183613f9c5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156136b657818101518382015260200161369e565b506000838581613fa857fe5b0495945050505050565b60006003821115613ff5575080600160028204015b81811015613fef57809150600281828581613fde57fe5b040181613fe757fe5b049050613fc7565b506121fc565b81156121fc57506001919050565b6114dd85858585856110a8565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed5141561403f575060006121fc565b6001600160a01b038216735d3a536e4d6dbd6114cc1ead35777bab948e3643141561407f5750736b175474e89094c44da98b954eedeac495271d0f6121fc565b6001600160a01b038216736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e14156140bf5750730d8775f648430679a709e98d2b0cb6250d2887ef6121fc565b6001600160a01b03821673158079ee67fce2f58472a96584a73c7ab9ac95c114156140ff5750731985365e9f78359a9b6ad760e32412f4a445e8626121fc565b6001600160a01b0382167339aa39c021dfbae8fac545936693ac917d5e7563141561413f575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486121fc565b6001600160a01b03821673c11b1268c1a384e55c48c2391d8d480264a3a7f4141561417f5750732260fac5e5542a773aa44fbcfedf7c193bc2c5996121fc565b6001600160a01b03821673b3319f5d18bc0d84dd1b4825dcde5d5f7266d40714156141bf575073e41d2489571d322189246dafa5ebde1f4699f4986121fc565b6001600160a01b03821673f650c3d88d12db855b8bf7d11be6c55a4e07dcc914156141ff575073dac17f958d2ee523a2206206994597c13d831ec76121fc565b50600019919050565b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614230576114dd565b61424181608063ffffffff61237316565b61445c57600061425086614469565b90506001600160a01b03808216146142d357856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156142a857600080fd5b505af11580156142bc573d6000803e3d6000fd5b505050506142cd8186868686614211565b506114dd565b6142dc85614469565b90506001600160a01b038082161461445a576142fb8682868686614893565b60006143166001600160a01b0383163063ffffffff611cb616565b905061439a8273398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b15801561436957600080fd5b505afa15801561437d573d6000803e3d6000fd5b505050506040513d602081101561439357600080fd5b5051611805565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666143c66001600160a01b0385166121c5565b6143d15760006143d3565b825b6143e5856001600160a01b03166121c5565b6143ef5784614405565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b15801561218e57600080fd5b505b6114dd8585858585614893565b60006001600160a01b038216733a3a65aab0dd2a17e3f1947ba16138cd37d08c041415614498575060006121fc565b6001600160a01b03821673fc1e690f61efd961294b3e1ce3313fbd8aa4f85d14156144d85750736b175474e89094c44da98b954eedeac495271d0f6121fc565b6001600160a01b038216739ba00d6856a4edf4665bca2c2309936572473b7e1415614518575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486121fc565b6001600160a01b03821673625ae63000f46200499120b906716420bd059240141561455857507357ab1ec28d129707052df4df418d58a2d46d5f516121fc565b6001600160a01b038216736ee0f7bb50a54ab5253da0667b0dc2ee526c30a814156145985750734fabb145d64652a948d72533023f6e7a623c7c536121fc565b6001600160a01b038216734da9b813057d04baef4e5800e36083717b4a034114156145d357506e085d4780b73119b644ae5ecd22b3766121fc565b6001600160a01b0382167371fc860f7d3a592a4a98740e39db31d25db65ae81415614613575073dac17f958d2ee523a2206206994597c13d831ec76121fc565b6001600160a01b03821673e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d0014156146535750730d8775f648430679a709e98d2b0cb6250d2887ef6121fc565b6001600160a01b038216739d91be44c06d373a8a226e1f3b146956083803eb1415614693575073dd974d5c2e2928dea5f71b9825b8b646686bd2006121fc565b6001600160a01b038216737d2d3688df45ce7c552e19c27e007673da9204b814156146d357507380fb784b7ed66730e8b1dbd9820afd29931aab036121fc565b6001600160a01b03821673a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f841415614713575073514910771af9ca656af840dff83e8264ecf986ca6121fc565b6001600160a01b038216736fce4a401b6b80ace52baaefe4421bd188e76f6f14156147535750730f5d2fb29fb7d3cfee444a200298f468908cc9426121fc565b6001600160a01b038216737deb5e830be29f91e298ba5ff1356bb7f814699814156147935750739f8f72aa9304c8b593d555f12ef6589cc3a579a26121fc565b6001600160a01b0382167371010a9d003445ac60c4e6a7017c1e89a477b43814156147d35750731985365e9f78359a9b6ad760e32412f4a445e8626121fc565b6001600160a01b03821673328c4c80bc7aca0834db37e6600a6c49e12da4de1415614813575073c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6121fc565b6001600160a01b03821673fc4b8ed459e00e5400be803a9bb3954234fd50e314156148535750732260fac5e5542a773aa44fbcfedf7c193bc2c5996121fc565b6001600160a01b038216736fb0855c404e09c47c3fbca25f08d4e41f9f062f14156141ff575073e41d2489571d322189246dafa5ebde1f4699f4986121fc565b836001600160a01b0316856001600160a01b031614156148b2576114dd565b6148c48161040063ffffffff61237316565b614b65576000546001600160a01b0386811691161415614a1e576000805460408051637f8661a160e01b81526004810187905290516001600160a01b0390921692637f8661a19260248084019382900301818387803b15801561492657600080fd5b505af115801561493a573d6000803e3d6000fd5b5050600154604080516370a0823160e01b81523060048201529051600094506001600160a01b0390921692506370a08231916024808301926020929190829003018186803b15801561498b57600080fd5b505afa15801561499f573d6000803e3d6000fd5b505050506040513d60208110156149b557600080fd5b5051905080156149fd57600180546060916149de916001600160a01b0316908890859087610d24565b6001549092506149fb91506001600160a01b0316878484876119dd565b505b6142cd736b175474e89094c44da98b954eedeac495271d0f86868686614b6e565b6000546001600160a01b0385811691161415614b6557614a5585736b175474e89094c44da98b954eedeac495271d0f858585614b6e565b600054614a8090736b175474e89094c44da98b954eedeac495271d0f906001600160a01b0316611805565b600054604080516370a0823160e01b815230600482015290516001600160a01b039092169163049878f391736b175474e89094c44da98b954eedeac495271d0f916370a0823191602480820192602092909190829003018186803b158015614ae757600080fd5b505afa158015614afb573d6000803e3d6000fd5b505050506040513d6020811015614b1157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015614b5157600080fd5b505af115801561127a573d6000803e3d6000fd5b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614b8d576114dd565b614b9e81604063ffffffff61237316565b614e28576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2151415614cc5576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b158015614c2057600080fd5b505af1158015614c34573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051613aef9350736b175474e89094c44da98b954eedeac495271d0f9250879183916370a0823191602480820192602092909190829003018186803b158015614c9257600080fd5b505afa158015614ca6573d6000803e3d6000fd5b505050506040513d6020811015614cbc57600080fd5b50518585614e31565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c2151415614e2857614d0b85736b175474e89094c44da98b954eedeac495271d0f858585614e31565b614d3d736b175474e89094c44da98b954eedeac495271d0f7306af07097c9eeb7fd685c692751d5c66db49c215611805565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c21592633b4da69f929091736b175474e89094c44da98b954eedeac495271d0f916370a08231916024808301926020929190829003018186803b158015614dae57600080fd5b505afa158015614dc2573d6000803e3d6000fd5b505050506040513d6020811015614dd857600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015614b5157600080fd5b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614e50576114dd565b6114dd85858585856003546040516001600160a01b038781166024830190815287821660448401526064830187905260006084840181905260c4840186905260c060a48501908152875160e486015287519195606095941693637153a8af60e11b938c938c938c938a938d938d9391926101040190602080870191028083838a5b83811015614ee9578181015183820152602001614ed1565b50505050905001975050505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518082805190602001908083835b60208310614f5b5780518252601f199092019160209182019101614f3c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114614fbb576040519150601f19603f3d011682016040523d82523d6000602084013e614fc0565b606091505b50915091508160008114614fd35761174a565b3d60208301fd5b60405180604001604052806002906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a7231582032ba59a45ebd8200e8f33d827d0ce99f1c6cd2d6d89993c6d6345e099f90f30264736f6c634300050c00320000000000000000000000002ee196c22ce4795adfcd9d54b64040a6a7269d92000000000000000000000000cf8a85fc1cbefa2f8502c7334e9f58d6adabe2c3
Deployed Bytecode
0x6080604052600436106104525760003560e01c8063819faf7b1161023f578063c925777511610139578063d77366a4116100b6578063f4b9fa751161007a578063f4b9fa7514610cb4578063f56e281f14610cc9578063f69e204614610cde578063fa3f110b14610cf3578063fbe4ed9514610d0857610452565b8063d77366a414610b98578063dc1536b214610bad578063e2a7515e14610bc2578063e355812314610c8a578063e44987b414610c9f57610452565b8063cede5f6a116100fd578063cede5f6a14610abe578063d1ae606314610ad3578063d1aee5e3146105b7578063d393c3e914610b6e578063d70a2d1f14610b8357610452565b8063c925777514610a55578063c989b66714610a6a578063c9b42c6714610a7f578063cc26e9fc14610a94578063ce74b7ac14610aa957610452565b8063a734f06e116101c7578063bf2c5a071161018b578063bf2c5a07146109ec578063c11f4f1114610a01578063c762a46c14610a16578063c77b9de614610a2b578063c7f112e414610a4057610452565b8063a734f06e14610998578063b0a7ef29146109ad578063b184a3ae146109c2578063b3bc784414610857578063b69d0456146109d757610452565b80638ea812c01161020e5780638ea812c014610881578063944a32e214610896578063a1b4d01114610959578063a2878cb11461096e578063a4792ab31461098357610452565b8063819faf7b1461082d578063851954fa146108425780638aea49d2146108575780638bdb2afa1461086c57610452565b8063423d03f9116103505780635ae51b82116102d85780636cbc4a6e1161029c5780636cbc4a6e146107c457806375a8b012146107d957806375b5be2d146107ee5780637a88bdbd146108035780637e09b9c21461081857610452565b80635ae51b821461075b5780635c0cb4791461077057806364ec4e5c1461078557806368e2a0141461079a5780636b5a4ca2146107af57610452565b80634a7101d51161031f5780634a7101d5146106f25780635187c0911461070757806351f1985c1461071c57806352a701b4146107315780635aa8fb481461074657610452565b8063423d03f91461069e57806343ee21f0146106b357806344211d62146106c85780634752c680146106dd57610452565b80632d3b5207116103de5780633ca5b234116103a25780633ca5b2341461064a5780633e413bee1461065f5780633fc8cef31461067457806340ab7b8c146106895780634226a9b9146105e157610452565b80632d3b5207146105e15780632e707bd2146105f65780632f48ab7d1461060b57806334b4dabb14610620578063372a26cb1461063557610452565b8063139891401161042557806313989140146105785780631d209b651461058d5780632113240d146105a257806321a360f5146105b757806322320c98146105cc57610452565b806305d8aa0a14610461578063085e2c5b1461048857806312dea160146105325780631388b42014610563575b3332141561045f57600080fd5b005b34801561046d57600080fd5b50610476610d1d565b60408051918252519081900360200190f35b34801561049457600080fd5b506104d7600480360360a08110156104ab57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060800135610d24565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561051d578181015183820152602001610505565b50505050905001935050505060405180910390f35b34801561053e57600080fd5b50610547610e6c565b604080516001600160a01b039092168252519081900360200190f35b34801561056f57600080fd5b50610547610e84565b34801561058457600080fd5b50610476610e9c565b34801561059957600080fd5b50610476610ea2565b3480156105ae57600080fd5b50610476610eaa565b3480156105c357600080fd5b50610476610eb0565b3480156105d857600080fd5b50610547610eb9565b3480156105ed57600080fd5b50610476610ed1565b34801561060257600080fd5b50610476610ed9565b34801561061757600080fd5b50610547610ede565b34801561062c57600080fd5b50610476610ef6565b34801561064157600080fd5b50610547610efb565b34801561065657600080fd5b50610547610f13565b34801561066b57600080fd5b50610547610f2b565b34801561068057600080fd5b50610547610f43565b34801561069557600080fd5b50610547610f5b565b3480156106aa57600080fd5b50610547610f73565b3480156106bf57600080fd5b50610547610f8b565b3480156106d457600080fd5b50610476610f9a565b3480156106e957600080fd5b50610476610f9f565b3480156106fe57600080fd5b50610476610fa7565b34801561071357600080fd5b50610547610fac565b34801561072857600080fd5b50610547610fc4565b34801561073d57600080fd5b50610547610fdc565b34801561075257600080fd5b50610476610ff4565b34801561076757600080fd5b50610476610ffa565b34801561077c57600080fd5b50610476611000565b34801561079157600080fd5b50610476611005565b3480156107a657600080fd5b5061047661100c565b3480156107bb57600080fd5b50610547611013565b3480156107d057600080fd5b50610476611022565b3480156107e557600080fd5b50610476611029565b3480156107fa57600080fd5b5061054761102f565b34801561080f57600080fd5b50610476611042565b34801561082457600080fd5b50610476611047565b34801561083957600080fd5b5061054761104e565b34801561084e57600080fd5b50610547611066565b34801561086357600080fd5b5061047661107e565b34801561087857600080fd5b50610547611087565b34801561088d57600080fd5b5061047661109f565b61045f600480360360a08110156108ac57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156108e657600080fd5b8201836020820111156108f857600080fd5b803590602001918460208302840111600160201b8311171561091957600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955050913592506110a8915050565b34801561096557600080fd5b506105476114e4565b34801561097a57600080fd5b506104766114fc565b34801561098f57600080fd5b50610547611504565b3480156109a457600080fd5b5061054761151c565b3480156109b957600080fd5b50610476611534565b3480156109ce57600080fd5b5061054761153a565b3480156109e357600080fd5b50610547611552565b3480156109f857600080fd5b5061047661156a565b348015610a0d57600080fd5b50610547611572565b348015610a2257600080fd5b50610476611581565b348015610a3757600080fd5b50610476611586565b348015610a4c57600080fd5b5061047661158c565b348015610a6157600080fd5b50610547611594565b348015610a7657600080fd5b506104766115ac565b348015610a8b57600080fd5b506104766115b3565b348015610aa057600080fd5b506104766115ba565b348015610ab557600080fd5b506104766115bf565b348015610aca57600080fd5b506105476115c7565b348015610adf57600080fd5b5061045f600480360360a0811015610af657600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b811115610b3057600080fd5b820183602082011115610b4257600080fd5b803590602001918460208302840111600160201b83111715610b6357600080fd5b9193509150356115df565b348015610b7a57600080fd5b5061047661162c565b348015610b8f57600080fd5b50610547611633565b348015610ba457600080fd5b5061054761164b565b348015610bb957600080fd5b50610476611663565b61045f600480360360c0811015610bd857600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b811115610c1757600080fd5b820183602082011115610c2957600080fd5b803590602001918460208302840111600160201b83111715610c4a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250611669915050565b348015610c9657600080fd5b50610476611755565b348015610cab57600080fd5b5061047661175d565b348015610cc057600080fd5b50610547611765565b348015610cd557600080fd5b5061047661177d565b348015610cea57600080fd5b50610547611782565b348015610cff57600080fd5b5061047661179a565b348015610d1457600080fd5b506105476117a2565b6220000081565b6002546040805163085e2c5b60e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052608482018590529151600093606093169163085e2c5b9160a48083019287929190829003018186803b158015610d9057600080fd5b505afa158015610da4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015610dcd57600080fd5b815160208301805160405192949293830192919084600160201b821115610df357600080fd5b908301906020820185811115610e0857600080fd5b82518660208202830111600160201b82111715610e2457600080fd5b82525081516020918201928201910280838360005b83811015610e51578181015183820152602001610e39565b50505050905001604052505050915091509550959350505050565b7352ae12abe5d8bd778bd5397f99ca900624cfadd481565b73794e6e91555438afc3ccf1c5076a74f42133d08d81565b61200081565b630400000081565b61800081565b64020000000081565b73a5407eae9ba41422680e2e00537571bcc53efbfd81565b600160201b81565b608081565b73dac17f958d2ee523a2206206994597c13d831ec781565b604081565b7379a8c46dea5ada233abaffd40f3a0a2b1e5a4f2781565b734fabb145d64652a948d72533023f6e7a623c7c5381565b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b731f573d6fb3f13d689ff844b4ce37794d79a7ff1c81565b7345f783cce6b7ff23b2ab2d70e416cdb7d6055f5181565b6003546001600160a01b031681565b601081565b631e00000081565b602081565b735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b73a2b47e3d5c44877cca798226b7b8118f9bfb7a5681565b738e870d67f660d95d5be530380d0ec0bd388289e181565b61400081565b61080081565b600881565b6202000081565b6210000081565b6001546001600160a01b031681565b6208000081565b61040081565b6e085d4780b73119b644ae5ecd22b37681565b600281565b6240000081565b73398ec7346dcd622edc5ae82352f02be94c62d11981565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce31581565b64040000000081565b73c0a47dfe034b400b47bdad5fecda2621de6c4d9581565b64080000000081565b6110b0614fda565b6110b86117b1565b905060005b600281101561128b578181600281106110d257fe5b60200201516001600160a01b0316876001600160a01b031614156112835760008282600281106110fe57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561113b57600080fd5b505afa15801561114f573d6000803e3d6000fd5b505050506040513d602081101561116557600080fd5b50519050600083836002811061117757fe5b60200201516001600160a01b031663c85c93aa88600160006040519080825280602002602001820160405280156111b8578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015611218578181015183820152602001611200565b50505050905001945050505050602060405180830381600087803b15801561123f57600080fd5b505af1158015611253573d6000803e3d6000fd5b505050506040513d602081101561126957600080fd5b5051905061127a82898389896110a8565b505050506114dd565b6001016110bd565b5060005b60028110156114cd578181600281106112a457fe5b60200201516001600160a01b0316866001600160a01b031614156114c55760008282600281106112d057fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561130d57600080fd5b505afa158015611321573d6000803e3d6000fd5b505050506040513d602081101561133757600080fd5b5051905061134888828888886117f8565b6113628184846002811061135857fe5b6020020151611805565b82826002811061136e57fe5b60200201516001600160a01b0316633cfcef64826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156113d757600080fd5b505afa1580156113eb573d6000803e3d6000fd5b505050506040513d602081101561140157600080fd5b50516040805160008082526020820190925290506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561146a578181015183820152602001611452565b505050509050019350505050602060405180830381600087803b15801561149057600080fd5b505af11580156114a4573d6000803e3d6000fd5b505050506040513d60208110156114ba57600080fd5b506114dd9350505050565b60010161128f565b506114db86868686866117f8565b505b5050505050565b734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b634000000081565b737079e8517594e5b21d2b9a0d17cb33f5fe2bca7081565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b61100081565b7306364f10b501e868329afbc005b3492902d6c76381565b7306af07097c9eeb7fd685c692751d5c66db49c21581565b630800000081565b6000546001600160a01b031681565b600181565b61020081565b638000000081565b7357ab1ec28d129707052df4df418d58a2d46d5f5181565b6280000081565b6204000081565b601281565b630200000081565b7352ea46506b9cc5ef470c5bf89f17dc28bb35d85c81565b3330146115eb57600080fd5b6114db8686868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892506117f8915050565b6201000081565b73f6e2d7f616b67e46d708e4410746e9aab3a4c51881565b73818e6fecd516ecc3849daf6845e3ec868087b75581565b61010081565b33301461168b5761168b6001600160a01b03871633308763ffffffff6118be16565b61169886868685856119dd565b60006116b36001600160a01b0387163063ffffffff611cb616565b9050838110156116f45760405162461bcd60e51b81526004018080602001828103825260358152602001806150186035913960400191505060405180910390fd5b33301461174c576117156001600160a01b038716338363ffffffff611d6216565b5061174a336117336001600160a01b038a163063ffffffff611cb616565b6001600160a01b038a16919063ffffffff611d6216565b505b50505050505050565b631000000081565b632000000081565b736b175474e89094c44da98b954eedeac495271d0f81565b600481565b733d9819210a31b4961b30ef54be2aed79b9c9cd3b81565b630100000081565b6002546001600160a01b031681565b6117b9614fda565b50604080518082019091527310ec0d497824e342bcb0edce00959142aaa766dd815273eb66acc3d011056b00ea521f8203580c2e5d3991602082015290565b6114dd8585858585611de0565b611817826001600160a01b03166121c5565b6118ba5760408051636eb1769f60e11b81523060048201526001600160a01b038381166024830152915160ff9285169163dd62ed3e916044808301926020929190829003018186803b15801561186c57600080fd5b505afa158015611880573d6000803e3d6000fd5b505050506040513d602081101561189657600080fd5b5051901c6118ba576118ba6001600160a01b0383168260001963ffffffff61220116565b5050565b806118c8576119d7565b6118d1846121c5565b156119bc576001600160a01b038316331480156118ee5750803410155b6119295760405162461bcd60e51b815260040180806020018281038252602b81526020018061504d602b913960400191505060405180910390fd5b6001600160a01b0382163014611971576040516001600160a01b0383169082156108fc029083906000818181858888f1935050505015801561196f573d6000803e3d6000fd5b505b803411156119b757336108fc61198d348463ffffffff6122d716565b6040518115909202916000818181858888f193505050501580156119b5573d6000803e3d6000fd5b505b6119d7565b6119d76001600160a01b03851684848463ffffffff61231916565b50505050565b836001600160a01b0316856001600160a01b031614156119fc576114dd565b611a118164080000000063ffffffff61237316565b611ca9576000611a2086612379565b90506000611a2d86612379565b9050818015611a395750805b15611c6f5760608451604051908082528060200260200182016040528015611a6b578160200160208202803883390190505b50905060005b8551811015611abf57858181518110611a8657fe5b60200260200101516fffffffffffffffffffffffffffffffff16828281518110611aac57fe5b6020908102919091010152600101611a71565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b158015611b1557600080fd5b505afa158015611b29573d6000803e3d6000fd5b505050506040513d6020811015611b3f57600080fd5b50519050611b698973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc289856408000000006124a6565b60005b8651811015611bac576080878281518110611b8357fe5b6020026020010151901c838281518110611b9957fe5b6020908102919091010152600101611b6c565b50604080516370a0823160e01b8152306004820152905160009173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916370a0823191602480820192602092909190829003018186803b158015611c0257600080fd5b505afa158015611c16573d6000803e3d6000fd5b505050506040513d6020811015611c2c57600080fd5b50519050611c6573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a611c59848663ffffffff6122d716565b86640800000000612873565b50505050506114dd565b8115611c8e57611c87878787876408000000006124a6565b50506114dd565b8015611ca657611c8787878787640800000000612873565b50505b6114dd8585858585613376565b6000611cc1836121c5565b15611cd757506001600160a01b03811631611d5c565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611d2d57600080fd5b505afa158015611d41573d6000803e3d6000fd5b505050506040513d6020811015611d5757600080fd5b505190505b92915050565b600081611d7157506001611dd9565b611d7a846121c5565b15611dbb576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611db5573d6000803e3d6000fd5b50611dd9565b611dd56001600160a01b038516848463ffffffff61338316565b5060015b9392505050565b836001600160a01b0316856001600160a01b03161415611dff576114dd565b611e07614ff8565b611e0f6133d5565b9050611e238261080063ffffffff61237316565b6121b85760005b600d811015611fe2578181600d8110611e3f57fe5b60200201516001600160a01b0316876001600160a01b03161415611fda5760008282600d8110611e6b57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ea857600080fd5b505afa158015611ebc573d6000803e3d6000fd5b505050506040513d6020811015611ed257600080fd5b505190508282600d8110611ee257fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611f2c57600080fd5b505af1158015611f40573d6000803e3d6000fd5b50505050611fd28188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611f9f57600080fd5b505afa158015611fb3573d6000803e3d6000fd5b505050506040513d6020811015611fc957600080fd5b50518888611de0565b5050506114dd565b600101611e2a565b5060005b600d8110156121b6578181600d8110611ffb57fe5b60200201516001600160a01b0316866001600160a01b031614156121ae5760008282600d811061202757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561206457600080fd5b505afa158015612078573d6000803e3d6000fd5b505050506040513d602081101561208e57600080fd5b5051905061209f8882888888613542565b6120af818484600d811061135857fe5b8282600d81106120bb57fe5b60200201516001600160a01b031663b6b55f25826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561212457600080fd5b505afa158015612138573d6000803e3d6000fd5b505050506040513d602081101561214e57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561218e57600080fd5b505af11580156121a2573d6000803e3d6000fd5b505050505050506114dd565b600101611fe6565b505b6114db8686868686613542565b60006001600160a01b03821615806121f957506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b61220a836121c5565b6122d257600081118015612298575060408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561226a57600080fd5b505afa15801561227e573d6000803e3d6000fd5b505050506040513d602081101561229457600080fd5b5051115b156122b8576122b86001600160a01b03841683600063ffffffff61354f16565b6122d26001600160a01b038416838363ffffffff61354f16565b505050565b6000611dd983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613662565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526119d79085906136f9565b16151590565b6040805163c45a015560e01b60208083019190915282518083038201815291830192839052815160009384936060936001600160a01b038816936107d093918291908401908083835b602083106123e15780518252601f1990920191602091820191016123c2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114612442576040519150601f19603f3d011682016040523d82523d6000602084013e612447565b606091505b509150915081158061245857508051155b15612468576000925050506121fc565b80806020019051602081101561247d57600080fd5b50516001600160a01b0316735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f14949350505050565b6124c48573f164fc0ec4e93095b804a4795bbe1e041497b92a611805565b6124cc614fda565b6040518060400160405280876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561251057600080fd5b505afa158015612524573d6000803e3d6000fd5b505050506040513d602081101561253a57600080fd5b50516001600160a01b0390811682526040805163d21220a760e01b81529051602093840193928b169263d21220a79260048082019391829003018186803b15801561258457600080fd5b505afa158015612598573d6000803e3d6000fd5b505050506040513d60208110156125ae57600080fd5b50516001600160a01b0316905290506125c5614fda565b8151602083015173f164fc0ec4e93095b804a4795bbe1e041497b92a9163baa2abde9188600080306125f9426107086138b1565b604080516001600160e01b031960e08b901b1681526001600160a01b039889166004820152968816602488015260448701959095526064860193909352608485019190915290931660a483015260c4820192909252815160e480830193928290030181600087803b15801561266d57600080fd5b505af1158015612681573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060408110156126a657600080fd5b5084516040805182815260208084028201019091529192506060919080156126d8578160200160208202803883390190505b50905060005b6002811015612868578381600281106126f357fe5b60200201516001600160a01b0316886001600160a01b0316141561271657612860565b60005b865181101561275e578160080287828151811061273257fe5b6020026020010151901c60ff1683828151811061274b57fe5b6020908102919091010152600101612719565b503063e2a7515e85836002811061277157fe5b60200201518a86856002811061278357fe5b60200201516000878b6040518763ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561281d578181015183820152602001612805565b50505050905001975050505050505050600060405180830381600087803b15801561284757600080fd5b505af115801561285b573d6000803e3d6000fd5b505050505b6001016126de565b505050505050505050565b61287b614fda565b6040518060400160405280866001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b1580156128bf57600080fd5b505afa1580156128d3573d6000803e3d6000fd5b505050506040513d60208110156128e957600080fd5b50516001600160a01b0390811682526040805163d21220a760e01b81529051602093840193928a169263d21220a79260048082019391829003018186803b15801561293357600080fd5b505afa158015612947573d6000803e3d6000fd5b505050506040513d602081101561295d57600080fd5b50516001600160a01b031690529050612974614fda565b61298585600263ffffffff61390b16565b8082526129939086906122d7565b816001602002018181525050606084516040519080825280602002602001820160405280156129cc578160200160208202803883390190505b50905060005b6002811015612bc557612a098482600281106129ea57fe5b602002015173f164fc0ec4e93095b804a4795bbe1e041497b92a611805565b838160028110612a1557fe5b60200201516001600160a01b0316896001600160a01b03161415612a3857612bbd565b60005b8651811015612a805781600802878281518110612a5457fe5b6020026020010151901c60ff16838281518110612a6d57fe5b6020908102919091010152600101612a3b565b503063e2a7515e8a868460028110612a9457fe5b6020020151868560028110612aa557fe5b60200201516000878b6040518763ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015612b3f578181015183820152602001612b27565b50505050905001975050505050505050600060405180830381600087803b158015612b6957600080fd5b505af1158015612b7d573d6000803e3d6000fd5b50505050612bab30858360028110612b9157fe5b60200201516001600160a01b03169063ffffffff611cb616565b838260028110612bb757fe5b60200201525b6001016129d2565b50612bce614fda565b835160208086015185519186015173f164fc0ec4e93095b804a4795bbe1e041497b92a9363e8e337009390929160008030612c0b426107086138b1565b6040518963ffffffff1660e01b815260040180896001600160a01b03166001600160a01b03168152602001886001600160a01b03166001600160a01b03168152602001878152602001868152602001858152602001848152602001836001600160a01b03166001600160a01b0316815260200182815260200198505050505050505050606060405180830381600087803b158015612ca857600080fd5b505af1158015612cbc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506060811015612ce157600080fd5b5083518151919250148015612cfd575060208084015190820151145b15612d0b57505050506114dd565b805183516000911415612d1f576001612d22565b60005b6040805160028082526060808301845260ff9490941694509091602083019080388339019050509050858260028110612d5757fe5b602002015181600081518110612d6957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050858260010360028110612d9857fe5b602002015181600181518110612daa57fe5b6001600160a01b0390921660209283029190910190910152896000612df6858560028110612dd457fe5b6020020151888660028110612de557fe5b60200201519063ffffffff6122d716565b90506000612f318285600081518110612e0b57fe5b60200260200101516001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e6857600080fd5b505afa158015612e7c573d6000803e3d6000fd5b505050506040513d6020811015612e9257600080fd5b5051865187906001908110612ea357fe5b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612f0057600080fd5b505afa158015612f14573d6000803e3d6000fd5b505050506040513d6020811015612f2a57600080fd5b505161394d565b90506000606073f164fc0ec4e93095b804a4795bbe1e041497b92a620f42406338ed173960e01b85858a30612f6e4261070863ffffffff6138b116565b6040516024018086815260200185815260200180602001846001600160a01b03166001600160a01b03168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015612fdb578181015183820152602001612fc3565b505050509050019650505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518082805190602001908083835b6020831061304c5780518252601f19909201916020918201910161302d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d80600081146130af576040519150601f19603f3d011682016040523d82523d6000602084013e6130b4565b606091505b5091509150816130ce5750505050505050505050506114dd565b60608180602001905160208110156130e557600080fd5b8101908080516040519392919084600160201b82111561310457600080fd5b90830190602082018581111561311957600080fd5b82518660208202830111600160201b8211171561313557600080fd5b82525081516020918201928201910280838360005b8381101561316257818101518382015260200161314a565b50505050919091016040525092935073f164fc0ec4e93095b804a4795bbe1e041497b92a9250620f4240915062e8e33760e81b90508e600060200201518f600160200201518c156131c757856001815181106131ba57fe5b60200260200101516131ee565b6131ee866000815181106131d757fe5b60200260200101518b6122d790919063ffffffff16565b8d600114613210578660018151811061320357fe5b6020026020010151613237565b6132378760008151811061322057fe5b60200260200101518c6122d790919063ffffffff16565b6000803061324d4261070863ffffffff6138b116565b604080516001600160a01b03998a16602482015297891660448901526064880196909652608487019490945260a486019290925260c485015290931660e4830152610104808301939093528051808303909301835261012490910181526020820180516001600160e01b03166001600160e01b0319909416939093178352518151919290918291908083835b602083106132f85780518252601f1990920191602091820191016132d9565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d806000811461335b576040519150601f19603f3d011682016040523d82523d6000602084013e613360565b606091505b5050505050505050505050505050505050505050565b6114dd8585858585613998565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526122d29084906136f9565b6133dd614ff8565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b6114dd8585858585613cd1565b8015806135d5575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156135a757600080fd5b505afa1580156135bb573d6000803e3d6000fd5b505050506040513d60208110156135d157600080fd5b5051155b6136105760405162461bcd60e51b81526004018080602001828103825260368152602001806150a26036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526122d29084906136f9565b600081848411156136f15760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156136b657818101518382015260200161369e565b50505050905090810190601f1680156136e35780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b61370b826001600160a01b0316613f11565b61375c576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b6020831061379a5780518252601f19909201916020918201910161377b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146137fc576040519150601f19603f3d011682016040523d82523d6000602084013e613801565b606091505b509150915081613858576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156119d75780806020019051602081101561387457600080fd5b50516119d75760405162461bcd60e51b815260040180806020018281038252602a815260200180615078602a913960400191505060405180910390fd5b600082820183811015611dd9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611dd983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613f4d565b60006107ca6107cd8402046107ca613987600185038687600902028161396f57fe5b048687623cda2902028789623cda2002020103613fb2565b8161398e57fe5b0403949350505050565b836001600160a01b0316856001600160a01b031614156139b7576114dd565b6139ca816208000063ffffffff61237316565b613cc4576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613af457604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613a4c57600080fd5b505afa158015613a60573d6000803e3d6000fd5b505050506040513d6020811015613a7657600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015613ab657600080fd5b505af1158015613aca573d6000803e3d6000fd5b50505050613aef73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585614003565b6114dd565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415613b7257604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613a4c57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613c2557613bb88573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585613998565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0306001600160a01b0316316040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1157600080fd5b505af1158015611c65573d6000803e3d6000fd5b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415613cc457613c6b8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585613998565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0306001600160a01b0316316040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1157600080fd5b6114dd8585858585614003565b836001600160a01b0316856001600160a01b03161415613cf0576114dd565b613d0181601063ffffffff61237316565b613f04576000613d1086614010565b90506001600160a01b0380821614613dbf57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613d6857600080fd5b505af1158015613d7c573d6000803e3d6000fd5b505050506040513d6020811015613d9257600080fd5b5060009050613db06001600160a01b0383163063ffffffff611cb616565b9050611c878287838787613cd1565b613dc885614010565b90506001600160a01b0380821614613f0257613de78682868686614208565b6000613e026001600160a01b0383163063ffffffff611cb616565b9050613e16826001600160a01b03166121c5565b15613e8857734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e6a57600080fd5b505af1158015613e7e573d6000803e3d6000fd5b5050505050611c87565b613e928287611805565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015613ed857600080fd5b505af1158015613eec573d6000803e3d6000fd5b505050506040513d602081101561127a57600080fd5b505b6114dd8585858585614208565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613f4557508115155b949350505050565b60008183613f9c5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156136b657818101518382015260200161369e565b506000838581613fa857fe5b0495945050505050565b60006003821115613ff5575080600160028204015b81811015613fef57809150600281828581613fde57fe5b040181613fe757fe5b049050613fc7565b506121fc565b81156121fc57506001919050565b6114dd85858585856110a8565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed5141561403f575060006121fc565b6001600160a01b038216735d3a536e4d6dbd6114cc1ead35777bab948e3643141561407f5750736b175474e89094c44da98b954eedeac495271d0f6121fc565b6001600160a01b038216736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e14156140bf5750730d8775f648430679a709e98d2b0cb6250d2887ef6121fc565b6001600160a01b03821673158079ee67fce2f58472a96584a73c7ab9ac95c114156140ff5750731985365e9f78359a9b6ad760e32412f4a445e8626121fc565b6001600160a01b0382167339aa39c021dfbae8fac545936693ac917d5e7563141561413f575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486121fc565b6001600160a01b03821673c11b1268c1a384e55c48c2391d8d480264a3a7f4141561417f5750732260fac5e5542a773aa44fbcfedf7c193bc2c5996121fc565b6001600160a01b03821673b3319f5d18bc0d84dd1b4825dcde5d5f7266d40714156141bf575073e41d2489571d322189246dafa5ebde1f4699f4986121fc565b6001600160a01b03821673f650c3d88d12db855b8bf7d11be6c55a4e07dcc914156141ff575073dac17f958d2ee523a2206206994597c13d831ec76121fc565b50600019919050565b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614230576114dd565b61424181608063ffffffff61237316565b61445c57600061425086614469565b90506001600160a01b03808216146142d357856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156142a857600080fd5b505af11580156142bc573d6000803e3d6000fd5b505050506142cd8186868686614211565b506114dd565b6142dc85614469565b90506001600160a01b038082161461445a576142fb8682868686614893565b60006143166001600160a01b0383163063ffffffff611cb616565b905061439a8273398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b15801561436957600080fd5b505afa15801561437d573d6000803e3d6000fd5b505050506040513d602081101561439357600080fd5b5051611805565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666143c66001600160a01b0385166121c5565b6143d15760006143d3565b825b6143e5856001600160a01b03166121c5565b6143ef5784614405565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b15801561218e57600080fd5b505b6114dd8585858585614893565b60006001600160a01b038216733a3a65aab0dd2a17e3f1947ba16138cd37d08c041415614498575060006121fc565b6001600160a01b03821673fc1e690f61efd961294b3e1ce3313fbd8aa4f85d14156144d85750736b175474e89094c44da98b954eedeac495271d0f6121fc565b6001600160a01b038216739ba00d6856a4edf4665bca2c2309936572473b7e1415614518575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486121fc565b6001600160a01b03821673625ae63000f46200499120b906716420bd059240141561455857507357ab1ec28d129707052df4df418d58a2d46d5f516121fc565b6001600160a01b038216736ee0f7bb50a54ab5253da0667b0dc2ee526c30a814156145985750734fabb145d64652a948d72533023f6e7a623c7c536121fc565b6001600160a01b038216734da9b813057d04baef4e5800e36083717b4a034114156145d357506e085d4780b73119b644ae5ecd22b3766121fc565b6001600160a01b0382167371fc860f7d3a592a4a98740e39db31d25db65ae81415614613575073dac17f958d2ee523a2206206994597c13d831ec76121fc565b6001600160a01b03821673e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d0014156146535750730d8775f648430679a709e98d2b0cb6250d2887ef6121fc565b6001600160a01b038216739d91be44c06d373a8a226e1f3b146956083803eb1415614693575073dd974d5c2e2928dea5f71b9825b8b646686bd2006121fc565b6001600160a01b038216737d2d3688df45ce7c552e19c27e007673da9204b814156146d357507380fb784b7ed66730e8b1dbd9820afd29931aab036121fc565b6001600160a01b03821673a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f841415614713575073514910771af9ca656af840dff83e8264ecf986ca6121fc565b6001600160a01b038216736fce4a401b6b80ace52baaefe4421bd188e76f6f14156147535750730f5d2fb29fb7d3cfee444a200298f468908cc9426121fc565b6001600160a01b038216737deb5e830be29f91e298ba5ff1356bb7f814699814156147935750739f8f72aa9304c8b593d555f12ef6589cc3a579a26121fc565b6001600160a01b0382167371010a9d003445ac60c4e6a7017c1e89a477b43814156147d35750731985365e9f78359a9b6ad760e32412f4a445e8626121fc565b6001600160a01b03821673328c4c80bc7aca0834db37e6600a6c49e12da4de1415614813575073c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6121fc565b6001600160a01b03821673fc4b8ed459e00e5400be803a9bb3954234fd50e314156148535750732260fac5e5542a773aa44fbcfedf7c193bc2c5996121fc565b6001600160a01b038216736fb0855c404e09c47c3fbca25f08d4e41f9f062f14156141ff575073e41d2489571d322189246dafa5ebde1f4699f4986121fc565b836001600160a01b0316856001600160a01b031614156148b2576114dd565b6148c48161040063ffffffff61237316565b614b65576000546001600160a01b0386811691161415614a1e576000805460408051637f8661a160e01b81526004810187905290516001600160a01b0390921692637f8661a19260248084019382900301818387803b15801561492657600080fd5b505af115801561493a573d6000803e3d6000fd5b5050600154604080516370a0823160e01b81523060048201529051600094506001600160a01b0390921692506370a08231916024808301926020929190829003018186803b15801561498b57600080fd5b505afa15801561499f573d6000803e3d6000fd5b505050506040513d60208110156149b557600080fd5b5051905080156149fd57600180546060916149de916001600160a01b0316908890859087610d24565b6001549092506149fb91506001600160a01b0316878484876119dd565b505b6142cd736b175474e89094c44da98b954eedeac495271d0f86868686614b6e565b6000546001600160a01b0385811691161415614b6557614a5585736b175474e89094c44da98b954eedeac495271d0f858585614b6e565b600054614a8090736b175474e89094c44da98b954eedeac495271d0f906001600160a01b0316611805565b600054604080516370a0823160e01b815230600482015290516001600160a01b039092169163049878f391736b175474e89094c44da98b954eedeac495271d0f916370a0823191602480820192602092909190829003018186803b158015614ae757600080fd5b505afa158015614afb573d6000803e3d6000fd5b505050506040513d6020811015614b1157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015614b5157600080fd5b505af115801561127a573d6000803e3d6000fd5b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614b8d576114dd565b614b9e81604063ffffffff61237316565b614e28576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2151415614cc5576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b158015614c2057600080fd5b505af1158015614c34573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051613aef9350736b175474e89094c44da98b954eedeac495271d0f9250879183916370a0823191602480820192602092909190829003018186803b158015614c9257600080fd5b505afa158015614ca6573d6000803e3d6000fd5b505050506040513d6020811015614cbc57600080fd5b50518585614e31565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c2151415614e2857614d0b85736b175474e89094c44da98b954eedeac495271d0f858585614e31565b614d3d736b175474e89094c44da98b954eedeac495271d0f7306af07097c9eeb7fd685c692751d5c66db49c215611805565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c21592633b4da69f929091736b175474e89094c44da98b954eedeac495271d0f916370a08231916024808301926020929190829003018186803b158015614dae57600080fd5b505afa158015614dc2573d6000803e3d6000fd5b505050506040513d6020811015614dd857600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015614b5157600080fd5b6114dd85858585855b836001600160a01b0316856001600160a01b03161415614e50576114dd565b6114dd85858585856003546040516001600160a01b038781166024830190815287821660448401526064830187905260006084840181905260c4840186905260c060a48501908152875160e486015287519195606095941693637153a8af60e11b938c938c938c938a938d938d9391926101040190602080870191028083838a5b83811015614ee9578181015183820152602001614ed1565b50505050905001975050505050505050604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518082805190602001908083835b60208310614f5b5780518252601f199092019160209182019101614f3c565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d8060008114614fbb576040519150601f19603f3d011682016040523d82523d6000602084013e614fc0565b606091505b50915091508160008114614fd35761174a565b3d60208301fd5b60405180604001604052806002906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a7231582032ba59a45ebd8200e8f33d827d0ce99f1c6cd2d6d89993c6d6345e099f90f30264736f6c634300050c0032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002ee196c22ce4795adfcd9d54b64040a6a7269d92000000000000000000000000cf8a85fc1cbefa2f8502c7334e9f58d6adabe2c3
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x2eE196C22CE4795aDfcd9D54b64040a6A7269D92
Arg [1] : _oneSplit (address): 0xCf8a85fC1CBeFA2f8502c7334E9f58D6ADABe2C3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002ee196c22ce4795adfcd9d54b64040a6a7269d92
Arg [1] : 000000000000000000000000cf8a85fc1cbefa2f8502c7334e9f58d6adabe2c3
Deployed Bytecode Sourcemap
211357:3040:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;212090:10;212104:9;212090:23;;212082:32;;;;;;211357:3040;5018:59;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5018:59:0;;;:::i;:::-;;;;;;;;;;;;;;;;212130:615;;8:9:-1;5:2;;;30:1;27;20:12;5:2;212130:615:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;212130:615: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;212130:615:0;;;;;;;;;;;;;;;;;;37321:132;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37321:132:0;;;:::i;:::-;;;;-1:-1:-1;;;;;37321:132:0;;;;;;;;;;;;;;37746:105;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37746:105:0;;;:::i;4377:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4377:56:0;;;:::i;5539:63::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5539:63:0;;;:::i;4500:59::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4500:59:0;;;:::i;3501:69::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3501:69:0;;;:::i;38230:90::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38230:90:0;;;:::i;3398:71::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3398:71:0;;;:::i;3989:48::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3989:48:0;;;:::i;36355:80::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36355:80:0;;;:::i;3934:48::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3934:48:0;;;:::i;38135:88::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38135:88:0;;;:::i;36529:80::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36529:80:0;;;:::i;36268:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36268:80:0;;;:::i;36789:78::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36789:78:0;;;:::i;36182:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36182:79:0;;;:::i;38046:82::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38046:82:0;;;:::i;211795:25::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;211795:25:0;;;:::i;3817:52::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3817:52:0;;;:::i;5402:64::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5402:64:0;;;:::i;3876:51::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3876:51:0;;;:::i;38849:107::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38849:107:0;;;:::i;37858:89::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37858:89:0;;;:::i;36703:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36703:79:0;;;:::i;4440:53::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4440:53:0;;;:::i;4253:50::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4253:50:0;;;:::i;3761:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3761:49:0;;;:::i;4658:61::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4658:61:0;;;:::i;4878:63::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4878:63:0;;;:::i;106868:70::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;106868:70:0;;;:::i;4820:51::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4820:51:0;;;:::i;4197:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4197:49:0;;;:::i;36442:80::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36442:80:0;;;:::i;3342:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3342:49:0;;;:::i;5142:59::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5142:59:0;;;:::i;38418:100::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38418:100:0;;;:::i;36874:114::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36874:114:0;;;:::i;6117:60::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6117:60:0;;;:::i;37206:108::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37206:108:0;;;:::i;6184:72::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;6184:72:0;;;:::i;119078:1166::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;119078:1166:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;119078:1166:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;119078:1166:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;119078:1166:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;119078:1166:0;;-1:-1:-1;;119078:1166:0;;;-1:-1:-1;119078:1166:0;;-1:-1:-1;;119078:1166:0:i;38622:96::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38622:96:0;;;:::i;5825:66::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5825:66:0;;;:::i;38725:117::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38725:117:0;;;:::i;36000:87::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36000:87:0;;;:::i;4310:60::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4310:60:0;;;:::i;38327:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38327:84:0;;;:::i;36995:78::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36995:78:0;;;:::i;5609:63::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5609:63:0;;;:::i;106792:69::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;106792:69:0;;;:::i;3284:51::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3284:51:0;;;:::i;4107:58::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4107:58:0;;;:::i;5898:59::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5898:59:0;;;:::i;36616:80::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36616:80:0;;;:::i;5278:52::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5278:52:0;;;:::i;4751:62::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4751:62:0;;;:::i;35953:40::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;35953:40:0;;;:::i;5473:59::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5473:59:0;;;:::i;37954:85::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37954:85:0;;;:::i;118399:338::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118399:338:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;118399:338:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;118399:338:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;118399:338:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;118399:338:0;;-1:-1:-1;118399:338:0;-1:-1:-1;118399:338:0;;:::i;4566:60::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4566:60:0;;;:::i;37604:135::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37604:135:0;;;:::i;37082:117::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37082:117:0;;;:::i;4044:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;4044:56:0;;;:::i;212753:937::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;212753:937:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;212753:937:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;212753:937:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;212753:937:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;212753:937:0;;-1:-1:-1;;212753:937:0;;;-1:-1:-1;212753:937:0;;-1:-1:-1;;212753:937:0:i;5679:65::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5679:65:0;;;:::i;5751:67::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5751:67:0;;;:::i;36096:79::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;36096:79:0;;;:::i;3704:50::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;3704:50:0;;;:::i;38525:90::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;38525:90:0;;;:::i;5337:58::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;5337:58:0;;;:::i;211755:33::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;211755:33:0;;;:::i;5018:59::-;5069:8;5018:59;:::o;212130:615::-;212589:12;;:148;;;-1:-1:-1;;;212589:148:0;;-1:-1:-1;;;;;212589:148:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;212482:7;;212521:16;;212589:12;;:30;;:148;;;;;212482:7;;212589:148;;;;;;;:12;:148;;;5:2:-1;;;;30:1;27;20:12;5:2;212589:148:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;212589:148:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;212589:148:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;;;5:11;;2:2;;;29:1;26;19:12;2:2;212589:148:0;;;;;;;;;;;;;;;;;;;-1:-1:-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;-1:-1;;;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;212589:148:0;;421:4:-1;412:14;;;;212589:148:0;;;;;412:14:-1;212589:148: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;212589:148:0;;;;;;;;;;;212582:155;;;;212130:615;;;;;;;;:::o;37321:132::-;37410:42;37321:132;:::o;37746:105::-;37808:42;37746:105;:::o;4377:56::-;4427:6;4377:56;:::o;5539:63::-;5593:9;5539:63;:::o;4500:59::-;4553:6;4500:59;:::o;3501:69::-;3559:11;3501:69;:::o;38230:90::-;38277:42;38230:90;:::o;3398:71::-;-1:-1:-1;;;3398:71:0;:::o;3989:48::-;4033:4;3989:48;:::o;36355:80::-;36392:42;36355:80;:::o;3934:48::-;3978:4;3934:48;:::o;38135:88::-;38180:42;38135:88;:::o;36529:80::-;36566:42;36529:80;:::o;36268:::-;36305:42;36268:80;:::o;36789:78::-;36824:42;36789:78;:::o;36182:79::-;36218:42;36182:79;:::o;38046:82::-;38085:42;38046:82;:::o;211795:25::-;;;-1:-1:-1;;;;;211795:25:0;;:::o;3817:52::-;3865:4;3817:52;:::o;5402:64::-;5456:10;5402:64;:::o;3876:51::-;3923:4;3876:51;:::o;38849:107::-;38913:42;38849:107;:::o;37858:89::-;37904:42;37858:89;:::o;36703:79::-;36739:42;36703:79;:::o;4440:53::-;4487:6;4440:53;:::o;4253:50::-;4298:5;4253:50;:::o;3761:49::-;3806:4;3761:49;:::o;4658:61::-;4712:7;4658:61;:::o;4878:63::-;4933:8;4878:63;:::o;106868:70::-;;;-1:-1:-1;;;;;106868:70:0;;:::o;4820:51::-;4864:7;4820:51;:::o;4197:49::-;4241:5;4197:49;:::o;36442:80::-;36479:42;36442:80;:::o;3342:49::-;3387:4;3342:49;:::o;5142:59::-;5193:8;5142:59;:::o;38418:100::-;38475:42;38418:100;:::o;36874:114::-;36945:42;36874:114;:::o;6117:60::-;6166:11;6117:60;:::o;37206:108::-;37271:42;37206:108;:::o;6184:72::-;6245:11;6184:72;:::o;119078:1166::-;119271:22;;:::i;:::-;119296:13;:11;:13::i;:::-;119271:38;-1:-1:-1;119327:6:0;119322:371;119343:13;119339:1;:17;119322:371;;;119402:6;119409:1;119402:9;;;;;;;;;;;-1:-1:-1;;;;;119382:30:0;:9;-1:-1:-1;;;;;119382:30:0;;119378:304;;;119433:17;119453:6;119460:1;119453:9;;;;;;;;;;;-1:-1:-1;;;;;119453:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119453:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119453:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119453:17:0;;-1:-1:-1;119489:14:0;119506:6;119513:1;119506:9;;;;;;;;;;;-1:-1:-1;;;;;119506:25:0;;119532:6;119540:4;119560:1;119546:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;119546:16:0;;119506:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;119506:57:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119506:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119506:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119506:57:0;;-1:-1:-1;119582:59:0;119592:10;119604:7;119506:57;119621:12;119635:5;119582:9;:59::i;:::-;119660:7;;;;;;119378:304;119358:3;;119322:371;;;-1:-1:-1;119710:6:0;119705:452;119726:13;119722:1;:17;119705:452;;;119783:6;119790:1;119783:9;;;;;;;;;;;-1:-1:-1;;;;;119765:28:0;:7;-1:-1:-1;;;;;119765:28:0;;119761:385;;;119814:17;119834:6;119841:1;119834:9;;;;;;;;;;;-1:-1:-1;;;;;119834:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;119834:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;119834:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119834:17:0;;-1:-1:-1;119870:63:0;119882:9;119834:17;119905:6;119913:12;119927:5;119870:11;:63::i;:::-;119952:56;119977:10;119997:6;120004:1;119997:9;;;;;;;;;;;119952:24;:56::i;:::-;120027:6;120034:1;120027:9;;;;;;;;;;;-1:-1:-1;;;;;120027:23:0;;120051:10;-1:-1:-1;;;;;120051:20:0;;120080:4;120051:35;;;;;;;;;;;;;-1:-1:-1;;;;;120051:35:0;-1:-1:-1;;;;;120051:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120051:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120051:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;120051:35:0;120088:16;;;120102:1;120088:16;;;120051:35;120088:16;;;;;;;120027:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;120027:78:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120027:78:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120027:78:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;120124:7:0;;-1:-1:-1;;;;120124:7:0;119761:385;119741:3;;119705:452;;;;120176:60;120188:9;120199:7;120208:6;120216:12;120230:5;120176:11;:60::i;:::-;120169:67;119078:1166;;;;;;:::o;38622:96::-;38675:42;38622:96;:::o;5825:66::-;5881:10;5825:66;:::o;38725:117::-;38799:42;38725:117;:::o;36000:87::-;36044:42;36000:87;:::o;4310:60::-;4364:6;4310:60;:::o;38327:84::-;38368:42;38327:84;:::o;36995:78::-;37030:42;36995:78;:::o;5609:63::-;5663:9;5609:63;:::o;106792:69::-;;;-1:-1:-1;;;;;106792:69:0;;:::o;3284:51::-;3331:4;3284:51;:::o;4107:58::-;4160:5;4107:58;:::o;5898:59::-;5947:10;5898:59;:::o;36616:80::-;36653:42;36616:80;:::o;5278:52::-;5322:8;5278:52;:::o;4751:62::-;4806:7;4751:62;:::o;35953:40::-;35991:2;35953:40;:::o;5473:59::-;5523:9;5473:59;:::o;37954:85::-;37996:42;37954:85;:::o;118399:338::-;118623:10;118645:4;118623:27;118615:36;;;;;;118669:60;118681:9;118692:7;118701:6;118709:12;;118669:60;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;118723:5:0;;-1:-1:-1;118669:11:0;;-1:-1:-1;;118669:60:0:i;4566:::-;4619:7;4566:60;:::o;37604:135::-;37696:42;37604:135;:::o;37082:117::-;37156:42;37082:117;:::o;4044:56::-;4095:5;4044:56;:::o;212753:937::-;213093:10;213115:4;213093:27;213089:126;;213137:66;-1:-1:-1;;;;;213137:31:0;;213169:10;213189:4;213196:6;213137:66;:31;:66;:::i;:::-;213227:54;213233:9;213244:7;213253:6;213261:12;213275:5;213227;:54::i;:::-;213294:20;213317:41;-1:-1:-1;;;;;213317:26:0;;213352:4;213317:41;:26;:41;:::i;:::-;213294:64;;213393:9;213377:12;:25;;213369:91;;;;-1:-1:-1;;;213369:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;213477:10;213499:4;213477:27;213473:210;;213521:51;-1:-1:-1;;;;;213521:25:0;;213547:10;213559:12;213521:51;:25;:51;:::i;:::-;-1:-1:-1;213587:84:0;213615:10;213627:43;-1:-1:-1;;;;;213627:28:0;;213664:4;213627:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;213587:27:0;;;:84;;:27;:84;:::i;:::-;;213473:210;212753:937;;;;;;;:::o;5679:65::-;5734:10;5679:65;:::o;5751:67::-;5808:10;5751:67;:::o;36096:79::-;36132:42;36096:79;:::o;3704:50::-;3750:4;3704:50;:::o;38525:90::-;38572:42;38525:90;:::o;5337:58::-;5386:9;5337:58;:::o;211755:33::-;;;-1:-1:-1;;;;;211755:33:0;;:::o;116052:227::-;116097:15;;:::i;:::-;-1:-1:-1;116125:146:0;;;;;;;;;116153:42;116125:146;;116217:42;116125:146;;;;116052:227;:::o;113735:326::-;113918:135;113943:9;113967:7;113989:6;114010:12;114037:5;113918:10;:135::i;45802:262::-;45887:13;:5;-1:-1:-1;;;;;45887:11:0;;:13::i;:::-;45882:175;;45922:34;;;-1:-1:-1;;;45922:34:0;;45946:4;45922:34;;;;-1:-1:-1;;;;;45922:34:0;;;;;;;;;45960:3;;45922:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;45922:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;45922:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;45922:34:0;:41;;45917:129;;45990:40;-1:-1:-1;;;;;45990:22:0;;46013:2;-1:-1:-1;;45990:40:0;:22;:40;:::i;:::-;45802:262;;:::o;31431:617::-;31542:11;31538:50;;31570:7;;31538:50;31604:12;31610:5;31604;:12::i;:::-;31600:441;;;-1:-1:-1;;;;;31641:18:0;;31649:10;31641:18;:41;;;;;31676:6;31663:9;:19;;31641:41;31633:97;;;;-1:-1:-1;;;31633:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;31749:19:0;;31763:4;31749:19;31745:97;;31789:37;;-1:-1:-1;;;;;31789:29:0;;;:37;;;;;31819:6;;31789:37;;;;31819:6;31789:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;31789:37:0;31745:97;31872:6;31860:9;:18;31856:101;;;31899:10;:42;31919:21;:9;31933:6;31919:21;:13;:21;:::i;:::-;31899:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;31899:42:0;31856:101;31600:441;;;31989:40;-1:-1:-1;;;;;31989:22:0;;32012:4;32018:2;32022:6;31989:40;:22;:40;:::i;:::-;31431:617;;;;:::o;202686:2329::-;202886:7;-1:-1:-1;;;;;202873:20:0;:9;-1:-1:-1;;;;;202873:20:0;;202869:59;;;202910:7;;202869:59;202945:47;:5;6245:11;202945:47;:11;:47;:::i;:::-;202940:1912;;203009:20;203032:26;203048:9;203032:15;:26::i;:::-;203009:49;;203073:18;203094:24;203110:7;203094:15;:24::i;:::-;203073:45;;203139:15;:32;;;;;203158:13;203139:32;203135:1094;;;203192:21;203230:12;:19;203216:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;203216:34:0;-1:-1:-1;203192:58:0;-1:-1:-1;203274:6:0;203269:134;203290:12;:19;203286:1;:23;203269:134;;;203349:12;203362:1;203349:15;;;;;;;;;;;;;;203368:14;203349:34;203339:4;203344:1;203339:7;;;;;;;;;;;;;;;;;:44;203311:3;;203269:134;;;-1:-1:-1;203451:29:0;;;-1:-1:-1;;;203451:29:0;;203474:4;203451:29;;;;;;203423:25;;36824:42;;203451:14;;:29;;;;;;;;;;;;;;;36824:42;203451:29;;;5:2:-1;;;;30:1;27;20:12;5:2;203451:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;203451:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;203451:29:0;;-1:-1:-1;203501:218:0;203551:9;36824:42;203610:6;203639:4;6245:11;203501:27;:218::i;:::-;203745:6;203740:122;203761:12;:19;203757:1;:23;203740:122;;;203839:3;203820:12;203833:1;203820:15;;;;;;;;;;;;;;:22;;203810:4;203815:1;203810:7;;;;;;;;;;;;;;;;;:32;203782:3;;203740:122;;;-1:-1:-1;203909:29:0;;;-1:-1:-1;;;203909:29:0;;203932:4;203909:29;;;;;;203882:24;;36824:42;;203909:14;;:29;;;;;;;;;;;;;;;36824:42;203909:29;;;5:2:-1;;;;30:1;27;20:12;5:2;203909:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;203909:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;203909:29:0;;-1:-1:-1;203966:247:0;36824:42;204041:7;204071:39;203909:29;204092:17;204071:39;:20;:39;:::i;:::-;204133:4;6245:11;203966:25;:247::i;:::-;203959:254;;;;;;;203135:1094;204249:15;204245:292;;;204292:229;204342:9;204374:7;204404:6;204433:12;6245:11;204292:27;:229::i;:::-;204285:236;;;;204245:292;204557:13;204553:288;;;204598:227;204646:9;204678:7;204708:6;204737:12;6245:11;204598:25;:227::i;204553:288::-;202940:1912;;;204871:136;204897:9;204921:7;204943:6;204964:12;204991:5;204871:11;:136::i;32816:228::-;32894:7;32918:12;32924:5;32918;:12::i;:::-;32914:123;;;-1:-1:-1;;;;;;32954:11:0;;;32947:18;;32914:123;33005:5;-1:-1:-1;;;;;33005:15:0;;33021:3;33005:20;;;;;;;;;;;;;-1:-1:-1;;;;;33005:20:0;-1:-1:-1;;;;;33005:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33005:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;33005:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;33005:20:0;;-1:-1:-1;32914:123:0;32816:228;;;;:::o;31075:348::-;31161:4;31182:11;31178:55;;-1:-1:-1;31217:4:0;31210:11;;31178:55;31249:12;31255:5;31249;:12::i;:::-;31245:171;;;31278:37;;-1:-1:-1;;;;;31278:29:0;;;:37;;;;;31308:6;;31278:37;;;;31308:6;31278:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;31278:37:0;31245:171;;;31348:30;-1:-1:-1;;;;;31348:18:0;;31367:2;31371:6;31348:30;:18;:30;:::i;:::-;-1:-1:-1;31400:4:0;31245:171;31075:348;;;;;:::o;114069:1326::-;114273:7;-1:-1:-1;;;;;114260:20:0;:9;-1:-1:-1;;;;;114260:20:0;;114256:59;;;114297:7;;114256:59;114327:25;;:::i;:::-;114355:10;:8;:10::i;:::-;114327:38;-1:-1:-1;114383:31:0;:5;4298;114383:31;:11;:31;:::i;:::-;114378:930;;114436:6;114431:385;114452:14;114448:1;:18;114431:385;;;114516:7;114524:1;114516:10;;;;;;;;;;;-1:-1:-1;;;;;114496:31:0;:9;-1:-1:-1;;;;;114496:31:0;;114492:309;;;114552:17;114572:7;114580:1;114572:10;;;;;;;;;;;-1:-1:-1;;;;;114572:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114572:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114572:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114572:18:0;;-1:-1:-1;114613:7:0;114621:1;114613:10;;;;;;;;;;;-1:-1:-1;;;;;114613:19:0;;114633:6;114613:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114613:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114613:27:0;;;;114663:89;114674:10;114686:7;114695:10;-1:-1:-1;;;;;114695:20:0;;114724:4;114695:35;;;;;;;;;;;;;-1:-1:-1;;;;;114695:35:0;-1:-1:-1;;;;;114695:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114695:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114695:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114695:35:0;114732:12;114746:5;114663:10;:89::i;:::-;114775:7;;;;;114492:309;114468:3;;114431:385;;;-1:-1:-1;114837:6:0;114832:465;114853:14;114849:1;:18;114832:465;;;114915:7;114923:1;114915:10;;;;;;;;;;;-1:-1:-1;;;;;114897:29:0;:7;-1:-1:-1;;;;;114897:29:0;;114893:389;;;114951:17;114971:7;114979:1;114971:10;;;;;;;;;;;-1:-1:-1;;;;;114971:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;114971:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;114971:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;114971:18:0;;-1:-1:-1;115012:63:0;115024:9;114971:18;115047:6;115055:12;115069:5;115012:11;:63::i;:::-;115098:57;115123:10;115143:7;115151:1;115143:10;;;;;;115098:57;115178:7;115186:1;115178:10;;;;;;;;;;;-1:-1:-1;;;;;115178:18:0;;115197:10;-1:-1:-1;;;;;115197:20:0;;115226:4;115197:35;;;;;;;;;;;;;-1:-1:-1;;;;;115197:35:0;-1:-1:-1;;;;;115197:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115197:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115197:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115197:35:0;115178:55;;;-1:-1:-1;;;;;;115178:55:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;115178:55:0;;;;;;;-1:-1:-1;115178:55:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;115178:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115178:55:0;;;;115256:7;;;;;114893:389;114869:3;;114832:465;;;;114378:930;115327:60;115339:9;115350:7;115359:6;115367:12;115381:5;115327:11;:60::i;33634:166::-;33685:4;-1:-1:-1;;;;;33710:39:0;;;;:81;;-1:-1:-1;;;;;;33753:38:0;;31023:42;33753:38;33710:81;33702:90;;33634:166;;;;:::o;32507:301::-;32600:12;32606:5;32600;:12::i;:::-;32595:206;;32642:1;32633:6;:10;:52;;;;-1:-1:-1;32647:34:0;;;-1:-1:-1;;;32647:34:0;;32671:4;32647:34;;;;-1:-1:-1;;;;;32647:34:0;;;;;;;;;32684:1;;32647:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;32647:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;32647:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;32647:34:0;:38;32633:52;32629:117;;;32706:24;-1:-1:-1;;;;;32706:17:0;;32724:2;32728:1;32706:24;:17;:24;:::i;:::-;32760:29;-1:-1:-1;;;;;32760:17:0;;32778:2;32782:6;32760:29;:17;:29;:::i;:::-;32507:301;;;:::o;8196:136::-;8254:7;8281:43;8285:1;8288;8281:43;;;;;;;;;;;;;;;;;:3;:43::i;27730:204::-;27857:68;;;-1:-1:-1;;;;;27857:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;27857:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;27831:95:0;;27850:5;;27831:18;:95::i;35511:117::-;35602:12;35601:19;;;35511:117::o;193779:417::-;193944:59;;;-1:-1:-1;;;193944:59:0;;;;;;;;;;26:21:-1;;;22:32;;6:49;;193944:59:0;;;;;;;193894:120;;193841:4;;;;193873:17;;-1:-1:-1;;;;;193894:25:0;;;193924:4;;193944:59;;;193894:120;;;;;193944:59;193894:120;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;;;193894:120: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;;193858:156:0;;;;194030:7;194029:8;:28;;;-1:-1:-1;194041:11:0;;:16;194029:28;194025:73;;;194081:5;194074:12;;;;;;194025:73;194126:4;194115:27;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194115:27:0;-1:-1:-1;;;;;194115:73:0;194146:42;194115:73;;193779:417;-1:-1:-1;;;;193779:417:0:o;205023:1235::-;205227:59;205252:9;193727:42;205227:24;:59::i;:::-;205299:24;;:::i;:::-;:154;;;;;;;;205364:9;-1:-1:-1;;;;;205341:41:0;;:43;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;205341:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;205341:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;205341:43:0;-1:-1:-1;;;;;205299:154:0;;;;;205399:43;;;-1:-1:-1;;;205399:43:0;;;;205341;205299:154;;;;205399:41;;;;;;:43;;;;;;;;;;;:41;:43;;;5:2:-1;;;;30:1;27;20:12;5:2;205399:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;205399:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;205399:43:0;-1:-1:-1;;;;;205299:154:0;;;;-1:-1:-1;205466:25:0;;:::i;:::-;205538:9;;;205562;;;193727:42;;205494:29;;205586:6;205545:1;;205665:4;205685:13;:3;205693:4;205685:7;:13::i;:::-;205494:215;;;-1:-1:-1;;;;;;205494:215:0;;;;;;;-1:-1:-1;;;;;205494:215:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;205494:215:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;205494:215:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;205494:215:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;13:2;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;205760:19:0;;205746:34;;;;;;;;;;;;;;;;205494:215;;-1:-1:-1;205722:21:0;;205746:34;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;205746:34:0;-1:-1:-1;205722:58:0;-1:-1:-1;205796:6:0;205791:460;205812:1;205808;:5;205791:460;;;205852:6;205859:1;205852:9;;;;;;;;;;;-1:-1:-1;;;;;205841:20:0;:7;-1:-1:-1;;;;;205841:20:0;;205837:69;;;205882:8;;205837:69;205927:6;205922:127;205943:12;:19;205939:1;:23;205922:127;;;206019:1;206023;206019:5;205999:12;206012:1;205999:15;;;;;;;;;;;;;;:26;;206029:4;205998:35;205988:4;205993:1;205988:7;;;;;;;;;;;;;;;;;:45;205964:3;;205922:127;;;-1:-1:-1;206065:4:0;:9;206093:6;206100:1;206093:9;;;;;;;;;;;206121:7;206147;206155:1;206147:10;;;;;;;;;;;206176:1;206196:4;206219:5;206065:174;;;;;;;;;;;;;-1:-1:-1;;;;;206065:174:0;-1:-1:-1;;;;;206065:174:0;;;;;;-1:-1:-1;;;;;206065:174:0;-1:-1:-1;;;;;206065:174: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;206065:174:0;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;206065:174:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;206065:174:0;;;;205791:460;205815:3;;205791:460;;;;205023:1235;;;;;;;;:::o;206266:3315::-;206470:24;;:::i;:::-;:154;;;;;;;;206535:9;-1:-1:-1;;;;;206512:41:0;;:43;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;206512:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;206512:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;206512:43:0;-1:-1:-1;;;;;206470:154:0;;;;;206570:43;;;-1:-1:-1;;;206570:43:0;;;;206512;206470:154;;;;206570:41;;;;;;:43;;;;;;;;;;;:41;:43;;;5:2:-1;;;;30:1;27;20:12;5:2;206570:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;206570:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;206570:43:0;-1:-1:-1;;;;;206470:154:0;;;;-1:-1:-1;206687:25:0;;:::i;:::-;206736:13;:6;206747:1;206736:13;:10;:13;:::i;:::-;206723:26;;;206773:22;;:6;;:10;:22::i;:::-;206760:7;206768:1;206760:10;;;:35;;;;;206806:21;206844:12;:19;206830:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;206830:34:0;-1:-1:-1;206806:58:0;-1:-1:-1;206880:6:0;206875:613;206896:1;206892;:5;206875:613;;;206921:59;206946:6;206953:1;206946:9;;;;;;;;;;;193727:42;206921:24;:59::i;:::-;207014:6;207021:1;207014:9;;;;;;;;;;;-1:-1:-1;;;;;207001:22:0;:9;-1:-1:-1;;;;;207001:22:0;;206997:71;;;207044:8;;206997:71;207089:6;207084:127;207105:12;:19;207101:1;:23;207084:127;;;207181:1;207185;207181:5;207161:12;207174:1;207161:15;;;;;;;;;;;;;;:26;;207191:4;207160:35;207150:4;207155:1;207150:7;;;;;;;;;;;;;;;;;:45;207126:3;;207084:127;;;-1:-1:-1;207227:4:0;:9;207255;207283:6;207290:1;207283:9;;;;;;;;;;;207311:7;207319:1;207311:10;;;;;;;;;;;207340:1;207360:4;207383:5;207227:176;;;;;;;;;;;;;-1:-1:-1;;;;;207227:176:0;-1:-1:-1;;;;;207227:176:0;;;;;;-1:-1:-1;;;;;207227:176:0;-1:-1:-1;;;;;207227:176: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;207227:176:0;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;207227:176:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;207227:176:0;;;;207433:43;207470:4;207433:6;207440:1;207433:9;;;;;;;;;;;-1:-1:-1;;;;;207433:28:0;;:43;:28;:43;:::i;:::-;207420:7;207428:1;207420:10;;;;;;;;;;:56;206875:613;206899:3;;206875:613;;;;207501:31;;:::i;:::-;207579:9;;;207603;;;;207627:10;;207652;;;;193727:42;;207538:26;;207579:9;;207603;207586:1;;207735:4;207755:13;:3;207763:4;207755:7;:13::i;:::-;207538:241;;;;;;;;;;;;;-1:-1:-1;;;;;207538:241:0;-1:-1:-1;;;;;207538:241:0;;;;;;-1:-1:-1;;;;;207538:241:0;-1:-1:-1;;;;;207538:241:0;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;207538:241:0;-1:-1:-1;;;;;207538:241:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;207538:241:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;207538:241:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;13:2;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;207830:10:0;;207810:16;;207538:241;;-1:-1:-1;207810:30:0;:77;;;;-1:-1:-1;207877:10:0;;;;;207857:16;;;;:30;207810:77;207792:140;;;207914:7;;;;;;207792:140;207982:16;;207968:10;;207944:21;;207968:30;;:38;;208005:1;207968:38;;;208001:1;207968:38;208040:15;;;208053:1;208040:15;;;208017:20;208040:15;;;;;207944:62;;;;;;-1:-1:-1;208040:15:0;;;;;;;105:10:-1;208040:15:0;88:34:-1;136:17;;-1:-1;208040:15:0;208017:38;;208076:6;208083:13;208076:21;;;;;;;;;;;208066:4;208071:1;208066:7;;;;;;;;;;;;;:31;-1:-1:-1;;;;;208066:31:0;;;-1:-1:-1;;;;;208066:31:0;;;;;208118:6;208129:13;208125:1;:17;208118:25;;;;;;;;;;;208108:4;208113:1;208108:7;;;;;;;;-1:-1:-1;;;;;208108:35:0;;;:7;;;;;;;;;;;:35;208185:9;208156:18;208243:56;208270:13;208284;208270:28;;;;;;;;;;;208243:7;208251:13;208243:22;;;;;;;;;;;;:56;:26;:56;:::i;:::-;208224:75;;208310:22;208335:142;208370:8;208393:4;208398:1;208393:7;;;;;;;;;;;;;;-1:-1:-1;;;;;208393:17:0;;208411:10;208393:29;;;;;;;;;;;;;-1:-1:-1;;;;;208393:29:0;-1:-1:-1;;;;;208393:29:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;208393:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208393:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208393:29:0;208437:7;;:4;;208442:1;;208437:7;;;;;;;;;;;;-1:-1:-1;;;;;208437:17:0;;208455:10;208437:29;;;;;;;;;;;;;-1:-1:-1;;;;;208437:29:0;-1:-1:-1;;;;;208437:29:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;208437:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208437:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208437:29:0;208335:20;:142::i;:::-;208310:167;-1:-1:-1;208491:12:0;208505:17;193727:42;208558:7;-1:-1:-1;;;208310:167:0;208491:12;208750:4;208781;208805:13;:3;208813:4;208805:13;:7;:13;:::i;:::-;208581:252;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;208581:252:0;-1:-1:-1;;;;;208581:252: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;208581:252:0;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;208581:252:0;;;;-1:-1:-1;;;;;208581:252:0;;38:4:-1;29:7;25:18;67:10;61:17;-1:-1;;;;;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;208581:252:0;208526:318;;;;;;;;;;;;;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;;;208526:318: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;;208490:354:0;;;;208862:7;208857:47;;208886:7;;;;;;;;;;;;;208857:47;208916:27;208957:4;208946:29;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;208946:29:0;;;;;;;;;;;;;-1:-1:-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;-1:-1;;;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;208946:29:0;;421:4:-1;412:14;;;;208946:29:0;;;;;412:14:-1;208946:29: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;;;-1:-1;;;;208946:29:0;;;;;;-1:-1:-1;208916:59:0;;-1:-1:-1;193727:42:0;;-1:-1:-1;209020:7:0;;-1:-1:-1;;;;209084:35:0;-1:-1:-1;209138:6:0;209145:1;209138:9;;;;209166:6;209173:1;209166:9;;;;209194:18;;:106;;209287:10;209298:1;209287:13;;;;;;;;;;;;;;209194:106;;;209236:27;209249:10;209260:1;209249:13;;;;;;;;;;;;;;209236:8;:12;;:27;;;;:::i;:::-;209319:13;209336:1;209319:18;:106;;209412:10;209423:1;209412:13;;;;;;;;;;;;;;209319:106;;;209361:27;209374:10;209385:1;209374:13;;;;;;;;;;;;;;209361:8;:12;;:27;;;;:::i;:::-;209452:1;;209510:4;209534:13;:3;209542:4;209534:13;:7;:13;:::i;:::-;209043:519;;;-1:-1:-1;;;;;209043:519:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;209043:519:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;209043:519:0;;;179:29:-1;;;;160:49;;208988:585:0;;;209043:519;;208988:585;;;;25:18:-1;208988:585: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;;;208988:585: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;;208988:585:0;;206266:3315;;;;;;;;;;;;;;;;;:::o;128835:325::-;129018:134;129042:9;129066:7;129088:6;129109:12;129136:5;129018:9;:134::i;27546:176::-;27655:58;;;-1:-1:-1;;;;;27655:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;27655:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;27629:85:0;;27648:5;;27629:18;:85::i;110286:943::-;110328:17;;:::i;:::-;-1:-1:-1;110358:863:0;;;;;;;;110387:42;110358:863;;110452:42;110358:863;;;;110517:42;110358:863;;;;;;;110582:42;110358:863;;;;110647:42;110358:863;;;;110712:42;110358:863;;;;110777:42;110358:863;;;;110842:42;110358:863;;;;110907:42;110358:863;;;;110972:42;110358:863;;;;111037:42;110358:863;;;;111102:42;110358:863;;;;111167:42;110358:863;;;;110286:943;:::o;93377:328::-;93560:137;93587:9;93611:7;93633:6;93654:12;93681:5;93560:12;:137::i;27942:621::-;28312:10;;;28311:62;;-1:-1:-1;28328:39:0;;;-1:-1:-1;;;28328:39:0;;28352:4;28328:39;;;;-1:-1:-1;;;;;28328:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;28328:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;28328:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28328:39:0;:44;28311:62;28303:152;;;;-1:-1:-1;;;28303:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28492:62;;;-1:-1:-1;;;;;28492:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;28492:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;28466:89:0;;28485:5;;28466:18;:89::i;8669:192::-;8755:7;8791:12;8783:6;;;;8775:29;;;;-1:-1:-1;;;8775:29: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;8775:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;8827:5:0;;;8669:192::o;29585:1114::-;30189:27;30197:5;-1:-1:-1;;;;;30189:25:0;;:27::i;:::-;30181:71;;;;;-1:-1:-1;;;30181:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;30326:12;30340:23;30375:5;-1:-1:-1;;;;;30367:19:0;30387:4;30367: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;;;30367: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;;30325:67:0;;;;30411:7;30403:52;;;;;-1:-1:-1;;;30403:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30472:17;;:21;30468:224;;30614:10;30603:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;30603:30:0;30595:85;;;;-1:-1:-1;;;30595:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7740:181;7798:7;7830:5;;;7854:6;;;;7846:46;;;;;-1:-1:-1;;;7846:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;10051:132;10109:7;10136:39;10140:1;10143;10136:39;;;;;;;;;;;;;;;;;:3;:39::i;194884:493::-;195049:7;195365:4;195358;195333:29;;:36;195326:4;195078:245;195310:1;195289:18;:22;195263;195238;195234:1;:26;:51;:78;;;;;;195196:22;195171;195161:7;:32;:57;195123:22;195112:8;195102:7;:18;:43;:116;:210;195078:9;:245::i;:::-;:252;;;;;;:291;;194884:493;-1:-1:-1;;;;194884:493:0:o;129168:1913::-;129371:7;-1:-1:-1;;;;;129358:20:0;:9;-1:-1:-1;;;;;129358:20:0;;129354:59;;;129395:7;;129354:59;129430:30;:5;4864:7;129430:30;:11;:30;:::i;:::-;129425:1493;;-1:-1:-1;;;;;129481:17:0;;36824:42;129481:17;129477:332;;;129533:29;;;-1:-1:-1;;;129533:29:0;;129556:4;129533:29;;;;;;36824:42;;129519:13;;36824:42;;129533:14;;:29;;;;;;;;;;;;;;36824:42;129533:29;;;5:2:-1;;;;30:1;27;20:12;5:2;129533:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129533:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129533:29:0;129519:44;;;-1:-1:-1;;;;;;129519:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;129519:44:0;;;;;;;-1:-1:-1;129519:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;129519:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129519:44:0;;;;129582:186;36044:42;129650:7;129680:6;129709:12;129744:5;129582:11;:186::i;:::-;129787:7;;129477:332;-1:-1:-1;;;;;129829:29:0;;36945:42;129829:29;129825:368;;;129905:41;;;-1:-1:-1;;;129905:41:0;;129940:4;129905:41;;;;;;36945:42;;129879:25;;36945:42;;129905:26;;:41;;;;;;;;;;;;;;36945:42;129905:41;;;5:2:-1;;;;30:1;27;20:12;129825:368:0;-1:-1:-1;;;;;130213:15:0;;36824:42;130213:15;130209:329;;;130249:186;130281:9;36044:42;130347:6;130376:12;130411:5;130249:9;:186::i;:::-;36824:42;-1:-1:-1;;;;;130454:12:0;;130481:4;-1:-1:-1;;;;;130473:21:0;;130454:43;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;130454:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;130209:329:0;-1:-1:-1;;;;;130558:27:0;;36945:42;130558:27;130554:353;;;130606:186;130638:9;36044:42;130704:6;130733:12;130768:5;130606:9;:186::i;:::-;36945:42;-1:-1:-1;;;;;130811:24:0;;130850:4;-1:-1:-1;;;;;130842:21:0;;130811:55;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;130554:353:0;130937:136;130963:9;130987:7;131009:6;131030:12;131057:5;130937:11;:136::i;93713:1743::-;93919:7;-1:-1:-1;;;;;93906:20:0;:9;-1:-1:-1;;;;;93906:20:0;;93902:59;;;93943:7;;93902:59;93978:34;:5;3865:4;93978:34;:11;:34;:::i;:::-;93973:1320;;94029:17;94049:38;94077:9;94049:27;:38::i;:::-;94029:58;-1:-1:-1;;;;;;94106:24:0;;;;94102:428;;94174:9;-1:-1:-1;;;;;94151:41:0;;94193:6;94151:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;94151:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;94151:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;94219:24:0;;-1:-1:-1;94246:44:0;-1:-1:-1;;;;;94246:29:0;;94284:4;94246:44;:29;:44;:::i;:::-;94219:71;;94318:196;94353:10;94386:7;94416:16;94455:12;94490:5;94318:12;:196::i;94102:428::-;94559:36;94587:7;94559:27;:36::i;:::-;94546:49;-1:-1:-1;;;;;;94614:24:0;;;;94610:672;;94659:187;94693:9;94725:10;94758:6;94787:12;94822:5;94659:11;:187::i;:::-;94867:24;94894:44;-1:-1:-1;;;;;94894:29:0;;94932:4;94894:44;:29;:44;:::i;:::-;94867:71;;94963:18;:10;-1:-1:-1;;;;;94963:16:0;;:18::i;:::-;94959:283;;;38675:42;-1:-1:-1;;;;;95006:9:0;;95022:16;95006:35;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;95006:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;95006:35:0;;;;;94959:283;;;95090:54;95115:10;95135:7;95090:24;:54::i;:::-;95190:7;-1:-1:-1;;;;;95167:37:0;;95205:16;95167:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;95167:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;95167:55:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;94610:672:0;93973:1320;;95312:136;95338:9;95362:7;95384:6;95405:12;95432:5;95312:11;:136::i;24575:619::-;24635:4;25103:20;;24946:66;25143:23;;;;;;:42;;-1:-1:-1;25170:15:0;;;25143:42;25135:51;24575:619;-1:-1:-1;;;;24575:619:0:o;10713:345::-;10799:7;10901:12;10894:5;10886:28;;;;-1:-1:-1;;;10886:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;10886:28:0;;10925:9;10941:1;10937;:5;;;;;;;10713:345;-1:-1:-1;;;;;10713:345:0:o;193274:303::-;193319:6;193346:1;193342;:5;193338:232;;;-1:-1:-1;193368:1:0;193401;193397;193393:5;;:9;193417:92;193428:1;193424;:5;193417:92;;;193454:1;193450:5;;193492:1;193487;193483;193479;:5;;;;;;:9;193478:15;;;;;;193474:19;;193417:92;;;193338:232;;;;193530:6;;193526:44;;-1:-1:-1;193557:1:0;193274:303;;;:::o;118745:325::-;118928:134;118952:9;118976:7;118998:6;119019:12;119046:5;118928:9;:134::i;89586:1409::-;89659:6;-1:-1:-1;;;;;89682:59:0;;89698:42;89682:59;89678:115;;;-1:-1:-1;89779:1:0;89765:16;;89678:115;-1:-1:-1;;;;;89807:59:0;;89823:42;89807:59;89803:156;;;-1:-1:-1;89904:42:0;89890:57;;89803:156;-1:-1:-1;;;;;89973:59:0;;89989:42;89973:59;89969:156;;;-1:-1:-1;90070:42:0;90056:57;;89969:156;-1:-1:-1;;;;;90139:59:0;;90155:42;90139:59;90135:156;;;-1:-1:-1;90236:42:0;90222:57;;90135:156;-1:-1:-1;;;;;90305:59:0;;90321:42;90305:59;90301:157;;;-1:-1:-1;90403:42:0;90389:57;;90301:157;-1:-1:-1;;;;;90472:59:0;;90488:42;90472:59;90468:157;;;-1:-1:-1;90570:42:0;90556:57;;90468:157;-1:-1:-1;;;;;90639:59:0;;90655:42;90639:59;90635:156;;;-1:-1:-1;90736:42:0;90722:57;;90635:156;-1:-1:-1;;;;;90805:59:0;;90821:42;90805:59;90801:157;;;-1:-1:-1;90903:42:0;90889:57;;90801:157;-1:-1:-1;;;89586:1409:0;;;:::o;125211:325::-;125394:134;125418:9;125442:7;125464:6;125485:12;125512:5;125544:1621;125747:7;-1:-1:-1;;;;;125734:20:0;:9;-1:-1:-1;;;;;125734:20:0;;125730:59;;;125771:7;;125730:59;125806:30;:5;4033:4;125806:30;:11;:30;:::i;:::-;125801:1201;;125853:17;125873:34;125897:9;125873:23;:34::i;:::-;125853:54;-1:-1:-1;;;;;;125926:24:0;;;;125922:321;;125990:9;-1:-1:-1;;;;;125971:37:0;;126009:6;125971:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;125971:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;125971:45:0;;;;126044:183;126076:10;126109:7;126139:6;126168:12;126203:5;126044:9;:183::i;:::-;126037:190;;;125922:321;126272:32;126296:7;126272:23;:32::i;:::-;126259:45;-1:-1:-1;;;;;;126323:24:0;;;;126319:672;;126368:187;126402:9;126434:10;126467:6;126496:12;126531:5;126368:11;:187::i;:::-;126576:24;126603:44;-1:-1:-1;;;;;126603:29:0;;126641:4;126603:44;:29;:44;:::i;:::-;126576:71;;126668:49;126693:10;38475:42;-1:-1:-1;;;;;126705:9:0;;:11;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126705:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126705:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;126705:11:0;126668:24;:49::i;:::-;38475:42;126736:12;126755:18;-1:-1:-1;;;;;126755:16:0;;;:18::i;:::-;:41;;126795:1;126755:41;;;126776:16;126755:41;126820:18;:10;-1:-1:-1;;;;;126820:16:0;;:18::i;:::-;:45;;126855:10;126820:45;;;36044:42;126820:45;126736:214;;;-1:-1:-1;;;;;;126736:214:0;;;;;;;-1:-1:-1;;;;;126736:214:0;;;;;;;;;;;;;126927:4;126736:214;;;;;;;;;;-1:-1:-1;;126736:214:0;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;126319:672:0;125801:1201;;127021:136;127047:9;127071:7;127093:6;127114:12;127141:5;127021:11;:136::i;120358:2905::-;120427:6;-1:-1:-1;;;;;120450:59:0;;120466:42;120450:59;120446:115;;;-1:-1:-1;120547:1:0;120533:16;;120446:115;-1:-1:-1;;;;;120575:59:0;;120591:42;120575:59;120571:156;;;-1:-1:-1;120672:42:0;120658:57;;120571:156;-1:-1:-1;;;;;120741:59:0;;120757:42;120741:59;120737:157;;;-1:-1:-1;120839:42:0;120825:57;;120737:157;-1:-1:-1;;;;;120908:59:0;;120924:42;120908:59;120904:157;;;-1:-1:-1;121006:42:0;120992:57;;120904:157;-1:-1:-1;;;;;121075:59:0;;121091:42;121075:59;121071:157;;;-1:-1:-1;121173:42:0;121159:57;;121071:157;-1:-1:-1;;;;;121242:59:0;;121258:42;121242:59;121238:157;;;-1:-1:-1;121340:42:0;121326:57;;121238:157;-1:-1:-1;;;;;121409:59:0;;121425:42;121409:59;121405:157;;;-1:-1:-1;121507:42:0;121493:57;;121405:157;-1:-1:-1;;;;;121576:59:0;;121592:42;121576:59;121572:156;;;-1:-1:-1;121673:42:0;121659:57;;121572:156;-1:-1:-1;;;;;121742:59:0;;121758:42;121742:59;121738:156;;;-1:-1:-1;121839:42:0;121825:57;;121738:156;-1:-1:-1;;;;;121908:59:0;;121924:42;121908:59;121904:157;;;-1:-1:-1;122006:42:0;121992:57;;121904:157;-1:-1:-1;;;;;122075:59:0;;122091:42;122075:59;122071:157;;;-1:-1:-1;122173:42:0;122159:57;;122071:157;-1:-1:-1;;;;;122242:59:0;;122258:42;122242:59;122238:157;;;-1:-1:-1;122340:42:0;122326:57;;122238:157;-1:-1:-1;;;;;122409:59:0;;122425:42;122409:59;122405:156;;;-1:-1:-1;122506:42:0;122492:57;;122405:156;-1:-1:-1;;;;;122575:59:0;;122591:42;122575:59;122571:156;;;-1:-1:-1;122672:42:0;122658:57;;122571:156;-1:-1:-1;;;;;122741:59:0;;122757:42;122741:59;122737:156;;;-1:-1:-1;122838:42:0;122824:57;;122737:156;-1:-1:-1;;;;;122907:59:0;;122923:42;122907:59;122903:157;;;-1:-1:-1;123005:42:0;122991:57;;122903:157;-1:-1:-1;;;;;123074:59:0;;123090:42;123074:59;123070:156;;;-1:-1:-1;123171:42:0;123157:57;;108242:1595;108442:7;-1:-1:-1;;;;;108429:20:0;:9;-1:-1:-1;;;;;108429:20:0;;108425:59;;;108466:7;;108425:59;108501:30;:5;4241;108501:30;:11;:30;:::i;:::-;108496:1254;;108572:4;;-1:-1:-1;;;;;108552:25:0;;;108572:4;;108552:25;108548:907;;;108598:4;;;:17;;;-1:-1:-1;;;108598:17:0;;;;;;;;;;-1:-1:-1;;;;;108598:4:0;;;;:9;;:17;;;;;;;;;;:4;;:17;;;5:2:-1;;;;30:1;27;20:12;5:2;108598:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;108657:3:0;;:28;;;-1:-1:-1;;;108657:28:0;;108679:4;108657:28;;;;;;108636:18;;-1:-1:-1;;;;;;108657:3:0;;;;-1:-1:-1;108657:13:0;;:28;;;;;;;;;;;;;;:3;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;108657:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108657:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;108657:28:0;;-1:-1:-1;108708:14:0;;108704:530;;108829:3;;;108749:32;;108785:201;;-1:-1:-1;;;;;108829:3:0;;108859:7;;108893:10;;108958:5;108785:17;:201::i;:::-;109043:3;;108747:239;;-1:-1:-1;109011:203:0;;-1:-1:-1;;;;;;109043:3:0;109073:7;109107:10;108747:239;109186:5;109011;:203::i;:::-;108704:530;;109261:178;36132:42;109321:7;109351:6;109380:12;109415:5;109261:11;:178::i;108548:907::-;109493:4;;-1:-1:-1;;;;;109475:23:0;;;109493:4;;109475:23;109471:268;;;109519:56;109531:9;36132:42;109547:6;109555:12;109569:5;109519:11;:56::i;:::-;109634:4;;109596:44;;36132:42;;-1:-1:-1;;;;;109634:4:0;109596:24;:44::i;:::-;109659:4;;109669:28;;;-1:-1:-1;;;109669:28:0;;109691:4;109669:28;;;;;;-1:-1:-1;;;;;109659:4:0;;;;:9;;36132:42;;109669:13;;:28;;;;;;;;;;;;;;;36132:42;109669:28;;;5:2:-1;;;;30:1;27;20:12;5:2;109669:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;109669:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;109669:28:0;109659:39;;;-1:-1:-1;;;;;;109659:39:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;109659:39:0;;;;;;;-1:-1:-1;109659:39:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;109659:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;109471:268:0;109769:60;109781:9;109792:7;109801:6;109809:12;109823:5;105267:1229;105467:7;-1:-1:-1;;;;;105454:20:0;:9;-1:-1:-1;;;;;105454:20:0;;105450:59;;;105491:7;;105450:59;105526:30;:5;3978:4;105526:30;:11;:30;:::i;:::-;105521:812;;-1:-1:-1;;;;;105577:25:0;;37030:42;105577:25;105573:326;;;105623:32;;;-1:-1:-1;;;105623:32:0;;105641:4;105623:32;;;;;;;;;;;;37030:42;;105623:9;;:32;;;;;-1:-1:-1;;105623:32:0;;;;;;;-1:-1:-1;37030:42:0;105623:32;;;5:2:-1;;;;30:1;27;20:12;5:2;105623:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;105773:28:0;;;-1:-1:-1;;;105773:28:0;;105795:4;105773:28;;;;;;105683:200;;-1:-1:-1;36132:42:0;;-1:-1:-1;105743:7:0;;36132:42;;105773:13;;:28;;;;;;;;;;;;;;;36132:42;105773:28;;;5:2:-1;;;;30:1;27;20:12;5:2;105773:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;105773:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;105773:28:0;105824:12;105859:5;105683:11;:200::i;105573:326::-;-1:-1:-1;;;;;105919:23:0;;37030:42;105919:23;105915:407;;;105963:180;105997:9;36132:42;106055:6;106084:12;106119:5;105963:11;:180::i;:::-;106164:44;36132:42;37030;106164:24;:44::i;:::-;106252:28;;;-1:-1:-1;;;106252:28:0;;106245:4;106252:28;;;;;;;;37030:42;;106227:9;;106245:4;;36132:42;;106252:13;;:28;;;;;;;;;;;;;;36132:42;106252:28;;;5:2:-1;;;;30:1;27;20:12;5:2;106252:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;106252:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;106252:28:0;106227:54;;;-1:-1:-1;;;;;;106227:54:0;;;;;;;-1:-1:-1;;;;;106227:54:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;106227:54:0;;;;;;;-1:-1:-1;106227:54:0;;;;5:2:-1;;;;30:1;27;20:12;105915:407:0;106352:136;106378:9;106402:7;106424:6;106445:12;106472:5;67607:431;67841:7;-1:-1:-1;;;;;67828:20:0;:9;-1:-1:-1;;;;;67828:20:0;;67824:59;;;67865:7;;67824:59;67895:135;67920:9;67944:7;67966:6;67987:12;68014:5;213930:8;;213967:228;;-1:-1:-1;;;;;213967:228:0;;;;;;;;;;;;;;;;;;;;;;213887:12;213967:228;;;;;;;;;;;;;;;;;;;;;;;;;;;213887:12;;213901:17;;213930:8;;;-1:-1:-1;;;214008:18:0;214045:9;;214073:7;;214099:6;;213887:12;;214144;;214175:5;;213967:228;;;;;;;;;;;;;;213887:12;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;213967:228:0;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;213967:228:0;;;;-1:-1:-1;;;;;213967:228:0;;38:4:-1;29:7;25:18;67:10;61:17;-1:-1;;;;;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;213967:228:0;213922:284;;;;;;;;;;;;;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;;;213922:284: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;;213886:320:0;;;;214250:7;214333:1;214328:48;;;;214243:133;;214328:48;214359:14;214354:2;214348:4;214344:13;214337:37;211357:3040;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;211357:3040:0;;;-1:-1:-1;;211357:3040:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;211357:3040:0;;;-1:-1:-1;;211357:3040:0:o
Swarm Source
bzzr://32ba59a45ebd8200e8f33d827d0ce99f1c6cd2d6d89993c6d6345e099f90f302
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BSC | 100.00% | $3.37 | 1 | $3.37 |
Loading...
Loading
[ Download: CSV Export ]
[ 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.