Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 10414687 | 1466 days ago | IN | Create: OneSplitViewWrap | 0 ETH | 0.06226576 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
OneSplitViewWrap
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-07-07 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/IOneSplit.sol pragma solidity ^0.5.0; // // [ msg.sender ] // | | // | | // \_/ // +---------------+ ________________________________ // | OneSplitAudit | _______________________________ \ // +---------------+ \ \ // | | ______________ | | (staticcall) // | | / ____________ \ | | // | | (call) / / \ \ | | // | | / / | | | | // \_/ | | \_/ \_/ // +--------------+ | | +----------------------+ // | OneSplitWrap | | | | OneSplitViewWrap | // +--------------+ | | +----------------------+ // | | | | | | // | | (delegatecall) | | (staticcall) | | (staticcall) // \_/ | | \_/ // +--------------+ | | +------------------+ // | OneSplit | | | | OneSplitView | // +--------------+ | | +------------------+ // | | / / // \ \________________/ / // \__________________/ // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01; uint256 internal constant DEPRECATED_FLAG_DISABLE_KYBER = 0x02; // Deprecated uint256 internal constant FLAG_DISABLE_BANCOR = 0x04; uint256 internal constant FLAG_DISABLE_OASIS = 0x08; uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10; uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20; uint256 internal constant FLAG_DISABLE_CHAI = 0x40; uint256 internal constant FLAG_DISABLE_AAVE = 0x80; uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_BDAI = 0x400; uint256 internal constant FLAG_DISABLE_IEARN = 0x800; uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 internal constant FLAG_DISABLE_WETH = 0x80000; uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_IDLE = 0x800000; uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000; uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000; uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000; uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000; uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000; uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000; uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_KYBER_ALL = 0x200000000000000; uint256 internal constant FLAG_DISABLE_KYBER_1 = 0x400000000000000; uint256 internal constant FLAG_DISABLE_KYBER_2 = 0x800000000000000; uint256 internal constant FLAG_DISABLE_KYBER_3 = 0x1000000000000000; uint256 internal constant FLAG_DISABLE_KYBER_4 = 0x2000000000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN_BY_ORIGIN = 0x4000000000000000; } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount); } contract IOneSplitMulti is IOneSplit { function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ); function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/interface/IUniswapExchange.sol pragma solidity ^0.5.0; interface IUniswapExchange { function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought); function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought); function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256 tokensBought); function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); } // File: contracts/interface/IKyberNetworkContract.sol pragma solidity ^0.5.0; interface IKyberNetworkContract { function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless) external view returns (address reserve, uint256 rate); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity ^0.5.0; interface IKyberNetworkProxy { function getExpectedRateAfterFee( IERC20 src, IERC20 dest, uint256 srcQty, uint256 platformFeeBps, bytes calldata hint ) external view returns (uint256 expectedRate); function tradeWithHintAndFee( IERC20 src, uint256 srcAmount, IERC20 dest, address payable destAddress, uint256 maxDestAmount, uint256 minConversionRate, address payable platformWallet, uint256 platformFeeBps, bytes calldata hint ) external payable returns (uint256 destAmount); 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/IKyberStorage.sol pragma solidity ^0.5.0; interface IKyberStorage { function getReserveIdsPerTokenSrc( IERC20 token ) external view returns (bytes32[] memory); } // File: contracts/interface/IKyberHintHandler.sol pragma solidity ^0.5.0; interface IKyberHintHandler { enum TradeType { BestOfAll, MaskIn, MaskOut, Split } function buildTokenToEthHint( IERC20 tokenSrc, TradeType tokenToEthType, bytes32[] calldata tokenToEthReserveIds, uint256[] calldata tokenToEthSplits ) external view returns (bytes memory hint); function buildEthToTokenHint( IERC20 tokenDest, TradeType ethToTokenType, bytes32[] calldata ethToTokenReserveIds, uint256[] calldata ethToTokenSplits ) external view returns (bytes memory hint); } // 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/IBancorNetworkPathFinder.sol pragma solidity ^0.5.0; interface IBancorNetworkPathFinder { function generatePath(IERC20 sourceToken, IERC20 targetToken) external view returns (address[] memory); } // 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/IBancorFinder.sol pragma solidity ^0.5.0; interface IBancorFinder { function buildBancorPath( IERC20 fromToken, IERC20 destToken ) external view returns(address[] memory path); } // File: contracts/interface/IOasisExchange.sol pragma solidity ^0.5.0; interface IOasisExchange { function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt) external view returns (uint256 fillAmt); function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount) external returns (uint256 fillAmt); } // File: contracts/interface/IWETH.sol pragma solidity ^0.5.0; contract IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/ICurve.sol pragma solidity ^0.5.0; interface ICurve { // solium-disable-next-line mixedcase function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external; // solium-disable-next-line mixedcase function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external; } contract ICurveRegistry { function get_pool_info(address pool) external view returns( uint256[8] memory balances, uint256[8] memory underlying_balances, uint256[8] memory decimals, uint256[8] memory underlying_decimals, address lp_token, uint256 A, uint256 fee ); } contract ICurveCalculator { function get_dy( int128 nCoins, uint256[8] calldata balances, uint256 amp, uint256 fee, uint256[8] calldata rates, uint256[8] calldata precisions, bool underlying, int128 i, int128 j, uint256[100] calldata dx ) external view returns(uint256[100] memory dy); } // File: contracts/interface/IChai.sol pragma solidity ^0.5.0; interface IPot { function dsr() external view returns (uint256); function chi() external view returns (uint256); function rho() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } contract IChai is IERC20 { function POT() public view returns (IPot); function join(address dst, uint256 wad) external; function exit(address src, uint256 wad) external; } library ChaiHelper { IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7); uint256 private constant RAY = 10**27; function _mul(uint256 x, uint256 y) private pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, y) / RAY; } function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, RAY) / y; } function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) { // solium-disable-next-line security/no-inline-assembly assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } function potDrip() private view returns (uint256) { return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi()); } function chaiPrice(IChai chai) internal view returns(uint256) { return chaiToDai(chai, 1e18); } function daiToChai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rdiv(amount, chi); } function chaiToDai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rmul(chi, amount); } } // File: contracts/interface/ICompound.sol pragma solidity ^0.5.0; contract ICompound { function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa); } contract ICompoundToken is IERC20 { function underlying() external view returns (address); function exchangeRateStored() external view returns (uint256); function mint(uint256 mintAmount) external returns (uint256); function redeem(uint256 redeemTokens) external returns (uint256); } contract ICompoundEther is IERC20 { function mint() external payable; function redeem(uint256 redeemTokens) external returns (uint256); } // File: contracts/interface/ICompoundRegistry.sol pragma solidity ^0.5.0; contract ICompoundRegistry { function tokenByCToken(ICompoundToken cToken) external view returns(IERC20); function cTokenByToken(IERC20 token) external view returns(ICompoundToken); } // 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/IAaveRegistry.sol pragma solidity ^0.5.0; contract IAaveRegistry { function tokenByAToken(IAaveToken aToken) external view returns(IERC20); function aTokenByToken(IERC20 token) external view returns(IAaveToken); } // File: contracts/interface/IMooniswap.sol pragma solidity ^0.5.0; interface IMooniswapRegistry { function target() external view returns(IMooniswap); } interface IMooniswap { function getReturn( IERC20 fromToken, IERC20 destToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn ) external payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/UniversalERC20.sol pragma solidity ^0.5.0; library UniversalERC20 { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) { if (amount == 0) { return true; } if (isETH(token)) { address(uint160(to)).transfer(amount); } else { token.safeTransfer(to, amount); return true; } } function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()"); if (to != address(this)) { address(uint160(to)).transfer(amount); } if (msg.value > amount) { msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(from, to, amount); } } function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { if (msg.value > amount) { // Return remainder if exist msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(msg.sender, address(this), amount); } } function universalApprove(IERC20 token, address to, uint256 amount) internal { if (!isETH(token)) { if (amount == 0) { token.safeApprove(to, 0); return; } uint256 allowance = token.allowance(address(this), to); if (allowance < amount) { if (allowance > 0) { token.safeApprove(to, 0); } token.safeApprove(to, amount); } } } function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); } } function universalDecimals(IERC20 token) internal view returns (uint256) { if (isETH(token)) { return 18; } (bool success, bytes memory data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("decimals()") ); if (!success || data.length == 0) { (success, data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("DECIMALS()") ); } return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18; } function isETH(IERC20 token) internal pure returns(bool) { return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS)); } function notExist(IERC20 token) internal pure returns(bool) { return (address(token) == address(-1)); } } // File: contracts/interface/IUniswapV2Exchange.sol pragma solidity ^0.5.0; interface IUniswapV2Exchange { function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; } library UniswapV2ExchangeLib { using SafeMath for uint256; using UniversalERC20 for IERC20; function getReturn( IUniswapV2Exchange exchange, IERC20 fromToken, IERC20 destToken, uint amountIn ) internal view returns (uint256) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = destToken.universalBalanceOf(address(exchange)); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); return (denominator == 0) ? 0 : numerator.div(denominator); } } // File: contracts/interface/IUniswapV2Factory.sol pragma solidity ^0.5.0; interface IUniswapV2Factory { function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair); } // File: contracts/interface/IDForceSwap.sol pragma solidity ^0.5.0; interface IDForceSwap { function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256); function swap(IERC20 input, IERC20 output, uint256 amount) external; } // File: contracts/interface/IShell.sol pragma solidity ^0.5.0; interface IShell { function viewOriginTrade( address origin, address target, uint256 originAmount ) external view returns (uint256); function swapByOrigin( address origin, address target, uint256 originAmount, uint256 minTargetAmount, uint256 deadline ) external returns (uint256); } // File: contracts/interface/IMStable.sol pragma solidity ^0.5.0; contract IMStable is IERC20 { function getSwapOutput( IERC20 _input, IERC20 _output, uint256 _quantity ) external view returns (bool, string memory, uint256 output); function swap( IERC20 _input, IERC20 _output, uint256 _quantity, address _recipient ) external returns (uint256 output); function redeem( IERC20 _basset, uint256 _bassetQuantity ) external returns (uint256 massetRedeemed); } interface IMassetRedemptionValidator { function getRedeemValidity( IERC20 _mAsset, uint256 _mAssetQuantity, IERC20 _outputBasset ) external view returns (bool, string memory, uint256 output); } // File: contracts/interface/IBalancerRegistry.sol pragma solidity ^0.5.0; interface IBalancerPool { function swapExactAmountIn( IERC20 tokenIn, uint256 tokenAmountIn, IERC20 tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter); } pragma solidity ^0.5.0; interface IBalancerRegistry { event PoolAdded( address indexed pool ); event PoolTokenPairAdded( address indexed pool, address indexed fromToken, address indexed destToken ); event IndicesUpdated( address indexed fromToken, address indexed destToken, bytes32 oldIndices, bytes32 newIndices ); // Get info about pool pair for 1 SLOAD function getPairInfo(address pool, address fromToken, address destToken) external view returns(uint256 weight1, uint256 weight2, uint256 swapFee); // Pools function checkAddedPools(address pool) external view returns(bool); function getAddedPoolsLength() external view returns(uint256); function getAddedPools() external view returns(address[] memory); function getAddedPoolsWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Tokens function getAllTokensLength() external view returns(uint256); function getAllTokens() external view returns(address[] memory); function getAllTokensWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Pairs function getPoolsLength(address fromToken, address destToken) external view returns(uint256); function getPools(address fromToken, address destToken) external view returns(address[] memory); function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit) external view returns(address[] memory result); function getBestPools(address fromToken, address destToken) external view returns(address[] memory pools); function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit) external view returns(address[] memory pools); // Get swap rates function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount) external view returns(uint256); function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts) external view returns(uint256[] memory result); // Add and update registry function addPool(address pool) external returns(uint256 listed); function addPools(address[] calldata pools) external returns(uint256[] memory listed); function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external; } // File: contracts/OneSplitBase.sol pragma solidity ^0.5.0; contract IOneSplitView is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns(bool) { return (flags & flag) != 0; } } contract OneSplitRoot is IOneSplitView { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20; using UniversalERC20 for IWETH; using UniswapV2ExchangeLib for IUniswapV2Exchange; using ChaiHelper for IChai; uint256 constant internal DEXES_COUNT = 31; IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D); IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847); IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380); IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6); IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e); IKyberStorage constant internal kyberStorage = IKyberStorage(0xC8fb12402cB16970F3C5F4b48Ff68Eb9D1289301); IKyberHintHandler constant internal kyberHintHandler = IKyberHintHandler(0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C); IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); //IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); IBancorFinder constant internal bancorFinder = IBancorFinder(0x2B344e14dc2641D11D338C053C908c7A7D4c30B9); IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D); ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); ICurve constant internal curveRenBTC = ICurve(0x93054188d876f558f4a66B2EF1d97d16eDf0895B); ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E); ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714); IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D); IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0x7079E8517594e5b21d2B9a0D17cb33F5FE2bca70); IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2); IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5); IMassetRedemptionValidator constant internal musd_helper = IMassetRedemptionValidator(0x4c5e03065bC52cCe84F3ac94DF14bbAC27eac89b); IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982); ICurveCalculator constant internal curveCalculator = ICurveCalculator(0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E); ICurveRegistry constant internal curveRegistry = ICurveRegistry(0x7002B727Ef8F5571Cb5F9D70D13DBEEb4dFAe9d1); ICompoundRegistry constant internal compoundRegistry = ICompoundRegistry(0xF451Dbd7Ba14BFa7B1B78A766D3Ed438F79EE1D1); IAaveRegistry constant internal aaveRegistry = IAaveRegistry(0xEd8b133B7B88366E01Bb9E38305Ab11c26521494); int256 internal constant VERY_NEGATIVE_VALUE = -1e72; function _findBestDistribution( uint256 s, // parts int256[][] memory amounts // exchangesReturns ) internal pure returns( int256 returnAmount, uint256[] memory distribution ) { uint256 n = amounts.length; int256[][] memory answer = new int256[][](n); // int[n][s+1] uint256[][] memory parent = new uint256[][](n); // int[n][s+1] for (uint i = 0; i < n; i++) { answer[i] = new int256[](s + 1); parent[i] = new uint256[](s + 1); } for (uint j = 0; j <= s; j++) { answer[0][j] = amounts[0][j]; for (uint i = 1; i < n; i++) { answer[i][j] = -1e72; } parent[0][j] = 0; } for (uint i = 1; i < n; i++) { for (uint j = 0; j <= s; j++) { answer[i][j] = answer[i - 1][j]; parent[i][j] = j; for (uint k = 1; k <= j; k++) { if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) { answer[i][j] = answer[i - 1][j - k] + amounts[i][k]; parent[i][j] = j - k; } } } } distribution = new uint256[](DEXES_COUNT); uint256 partsLeft = s; for (uint curExchange = n - 1; partsLeft > 0; curExchange--) { distribution[curExchange] = partsLeft - parent[curExchange][partsLeft]; partsLeft = parent[curExchange][partsLeft]; } returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s]; } function _kyberReserveIdByTokens( IERC20 fromToken, IERC20 destToken ) internal view returns(bytes32) { if (!fromToken.isETH() && !destToken.isETH()) { return 0; } bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc( fromToken.isETH() ? destToken : fromToken ); for (uint i = 0; i < reserveIds.length; i++) { if ((uint256(reserveIds[i]) >> 248) != 0xBB && // Bridge reserveIds[i] != 0xff4b796265722046707200000000000000000000000000000000000000000000 && // Reserve 1 reserveIds[i] != 0xffabcd0000000000000000000000000000000000000000000000000000000000 && // Reserve 2 reserveIds[i] != 0xff4f6e65426974205175616e7400000000000000000000000000000000000000) // Reserve 3 { return reserveIds[i]; } } return 0; } function _scaleDestTokenEthPriceTimesGasPrice( IERC20 fromToken, IERC20 destToken, uint256 destTokenEthPriceTimesGasPrice ) internal view returns(uint256) { if (fromToken == destToken) { return destTokenEthPriceTimesGasPrice; } uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 0.01 ether); uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 0.01 ether); if (div > 0) { return destTokenEthPriceTimesGasPrice.mul(mul).div(div); } return 0; } function _cheapGetPrice( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal view returns(uint256 returnAmount) { (returnAmount,,) = this.getExpectedReturnWithGas( fromToken, destToken, amount, 1, FLAG_DISABLE_SPLIT_RECALCULATION | FLAG_DISABLE_ALL_SPLIT_SOURCES | FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP, 0 ); } function _linearInterpolation( uint256 value, uint256 parts ) internal pure returns(uint256[] memory rets) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) { return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB); } } contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = this.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _getExpectedReturnRespectingGasFloor( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } contract OneSplitView is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); if (fromToken == destToken) { return (amount, 0, distribution); } function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags); int256[][] memory matrix = new int256[][](DEXES_COUNT); uint256[DEXES_COUNT] memory gases; bool atLeastOnePositive = false; for (uint i = 0; i < DEXES_COUNT; i++) { uint256[] memory rets; (rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags); // Prepend zero and sub gas int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18)); matrix[i] = new int256[](parts + 1); for (uint j = 0; j < parts; j++) { matrix[i][j + 1] = int256(rets[j]) - gas; atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0); } } if (!atLeastOnePositive) { for (uint i = 0; i < DEXES_COUNT; i++) { for (uint j = 1; j < parts + 1; j++) { if (matrix[i][j] == 0) { matrix[i][j] = VERY_NEGATIVE_VALUE; } } } } (, distribution) = _findBestDistribution(parts, matrix); (returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution( Args({ fromToken: fromToken, destToken: destToken, amount: amount, parts: parts, flags: flags, destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice, distribution: distribution, matrix: matrix, gases: gases, reserves: reserves }) ); return (returnAmount, estimateGasAmount, distribution); } struct Args { IERC20 fromToken; IERC20 destToken; uint256 amount; uint256 parts; uint256 flags; uint256 destTokenEthPriceTimesGasPrice; uint256[] distribution; int256[][] matrix; uint256[DEXES_COUNT] gases; function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] reserves; } function _getReturnAndGasByDistribution( Args memory args ) internal view returns(uint256 returnAmount, uint256 estimateGasAmount) { bool[DEXES_COUNT] memory exact = [ true, // "Uniswap", false, // "Kyber", false, // "Bancor", false, // "Oasis", true, // "Curve Compound", true, // "Curve USDT", true, // "Curve Y", true, // "Curve Binance", true, // "Curve Synthetix", true, // "Uniswap Compound", true, // "Uniswap CHAI", true, // "Uniswap Aave", false, // "Mooniswap", true, // "Uniswap V2", true, // "Uniswap V2 (ETH)", true, // "Uniswap V2 (DAI)", true, // "Uniswap V2 (USDC)", true, // "Curve Pax", true, // "Curve RenBTC", true, // "Curve tBTC", true, // "Dforce XSwap", false, // "Shell", true, // "mStable", true, // "Curve sBTC" true, // "Balancer 1" true, // "Balancer 2" true, // "Balancer 3" true, // "Kyber 1" true, // "Kyber 2" true, // "Kyber 3" true // "Kyber 4" ]; for (uint i = 0; i < DEXES_COUNT; i++) { if (args.distribution[i] > 0) { if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add(uint256( (value == VERY_NEGATIVE_VALUE ? 0 : value) + int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18)) )); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves(uint256 flags) internal pure returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory) { bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); return [ invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap, _calculateNoReturn, // invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC, invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap, invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell, invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_1) ? _calculateNoReturn : calculateKyber1, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_2) ? _calculateNoReturn : calculateKyber2, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_3) ? _calculateNoReturn : calculateKyber3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_4) ? _calculateNoReturn : calculateKyber4 ]; } function _calculateNoGas( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*parts*/, uint256 /*destTokenEthPriceTimesGasPrice*/, uint256 /*flags*/, uint256 /*destTokenEthPrice*/ ) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) { this; } // View Helpers function _calculateBalancer( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/, uint256 poolIndex ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (poolIndex >= pools.length) { return (rets, 0); } (bool success, bytes memory result) = address(balancerRegistry).staticcall( abi.encodeWithSelector( balancerRegistry.getPoolReturns.selector, pools[poolIndex], address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), _linearInterpolation(amount, parts) ) ); if (!success || result.length == 0) { return (rets, 0); } return ( abi.decode(result, (uint256[])), 100_000 ); } function calculateBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 0 ); } function calculateBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 1 ); } function calculateBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 2 ); } function calculateMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) || (destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd)) { return (rets, 0); } for (uint i = 1; i <= parts; i *= 2) { (bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector( musd.getSwapOutput.selector, fromToken, destToken, amount.mul(parts.div(i)).div(parts) )); if (success && data.length > 0) { (,, uint256 maxRet) = abi.decode(data, (bool,string,uint256)); if (maxRet > 0) { for (uint j = 0; j < parts.div(i); j++) { rets[j] = maxRet.mul(j + 1).div(parts.div(i)); } break; } } } return ( rets, 700_000 ); } function _getCurvePoolInfo( ICurve curve, bool haveUnderlying ) internal view returns( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) { uint256[8] memory underlying_balances; uint256[8] memory decimals; uint256[8] memory underlying_decimals; ( balances, underlying_balances, decimals, underlying_decimals, /*address lp_token*/, amp, fee ) = curveRegistry.get_pool_info(address(curve)); for (uint k = 0; k < 8 && balances[k] > 0; k++) { precisions[k] = 10 ** (18 - (haveUnderlying ? underlying_decimals : decimals)[k]); if (haveUnderlying) { rates[k] = underlying_balances[k].mul(1e18).div(balances[k]); } else { rates[k] = 1e18; } } } function _calculateCurveSelector( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, ICurve curve, bool haveUnderlying, IERC20[] memory tokens ) internal view returns(uint256[] memory rets) { rets = new uint256[](parts); int128 i = 0; int128 j = 0; for (uint t = 0; t < tokens.length; t++) { if (fromToken == tokens[t]) { i = int128(t + 1); } if (destToken == tokens[t]) { j = int128(t + 1); } } if (i == 0 || j == 0) { return rets; } bytes memory data = abi.encodePacked( uint256(haveUnderlying ? 1 : 0), uint256(i - 1), uint256(j - 1), _linearInterpolation100(amount, parts) ); ( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) = _getCurvePoolInfo(curve, haveUnderlying); bool success; (success, data) = address(curveCalculator).staticcall( abi.encodePacked( abi.encodeWithSelector( curveCalculator.get_dy.selector, tokens.length, balances, amp, fee, rates, precisions ), data ) ); if (!success || data.length == 0) { return rets; } uint256[100] memory dy = abi.decode(data, (uint256[100])); for (uint t = 0; t < parts; t++) { rets[t] = dy[t]; } } function _linearInterpolation100( uint256 value, uint256 parts ) internal pure returns(uint256[100] memory rets) { for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function calculateCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = dai; tokens[1] = usdc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveCompound, true, tokens ), 720_000); } function calculateCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveUSDT, true, tokens ), 720_000); } function calculateCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = tusd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveY, true, tokens ), 1_400_000); } function calculateCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = busd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveBinance, true, tokens ), 1_400_000); } function calculateCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = susd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSynthetix, true, tokens ), 200_000); } function calculateCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = pax; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curvePAX, true, tokens ), 1_000_000); } function calculateCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = renbtc; tokens[1] = wbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveRenBTC, false, tokens ), 130_000); } function calculateCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = tbtc; tokens[1] = wbtc; tokens[2] = hbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveTBTC, false, tokens ), 145_000); } function calculateCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = renbtc; tokens[1] = wbtc; tokens[2] = sbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSBTC, false, tokens ), 150_000); } function calculateShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector( shell.viewOriginTrade.selector, fromToken, destToken, amount )); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 300_000); } function calculateDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(dforceSwap).staticcall( abi.encodeWithSelector( dforceSwap.getAmountByInput.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); uint256 available = destToken.universalBalanceOf(address(dforceSwap)); if (maxRet > available) { return (new uint256[](parts), 0); } return (_linearInterpolation(maxRet, parts), 160_000); } function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) { if (amount == 0) { return 0; } return amount.mul(toBalance).mul(997).div( fromBalance.mul(1000).add(amount.mul(997)) ); } function _calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = amounts; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange)); uint256 fromEtherBalance = address(fromExchange).balance; for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 toEtherBalance = address(toExchange).balance; uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange)); for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]); } } return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000); } function calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswap( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function _calculateUniswapWrapped( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 midTokenPrice, uint256 flags, uint256 gas1, uint256 gas2 ) internal view returns(uint256[] memory rets, uint256 gas) { if (!fromToken.isETH() && destToken.isETH()) { (rets, gas) = _calculateUniswap( midToken, destToken, _linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts), flags ); return (rets, gas + gas1); } else if (fromToken.isETH() && !destToken.isETH()) { (rets, gas) = _calculateUniswap( fromToken, midToken, _linearInterpolation(amount, parts), flags ); for (uint i = 0; i < parts; i++) { rets[i] = rets[i].mul(midTokenPrice).div(1e18); } return (rets, gas + gas2); } return (new uint256[](parts), 0); } function calculateUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { ICompoundToken midToken = compoundRegistry.cTokenByToken(midPreToken); if (midToken != ICompoundToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, midToken.exchangeRateStored(), flags, 200_000, 200_000 ); } } return (new uint256[](parts), 0); } function calculateUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai && destToken.isETH() || fromToken.isETH() && destToken == dai) { return _calculateUniswapWrapped( fromToken, chai, destToken, amount, parts, chai.chaiPrice(), flags, 180_000, 160_000 ); } return (new uint256[](parts), 0); } function calculateUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { IAaveToken midToken = aaveRegistry.aTokenByToken(midPreToken); if (midToken != IAaveToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, 1e18, flags, 310_000, 670_000 ); } } return (new uint256[](parts), 0); } function calculateKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 // 0x63825c174ab367968EC60f061753D3bbD36A0D8F ); } function calculateKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 // 0x7a3370075a54B187d7bD5DceBf0ff2B5552d4F7D ); } function calculateKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 // 0x4f32BbE8dFc9efD54345Fc936f9fEF1048746fCF ); } function calculateKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { bytes32 reserveId = _kyberReserveIdByTokens(fromToken, destToken); if (reserveId == 0) { return (new uint256[](parts), 0); } return _calculateKyber( fromToken, destToken, amount, parts, flags, reserveId ); } function _kyberGetRate( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags, bytes memory hint ) private view returns(uint256) { (, bytes memory data) = address(kyberNetworkProxy).staticcall( abi.encodeWithSelector( kyberNetworkProxy.getExpectedRateAfterFee.selector, fromToken, destToken, amount, flags.check(1 << 255) ? 10 : 0, hint ) ); return (data.length == 32) ? abi.decode(data, (uint256)) : 0; } function _calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, bytes32 reserveId ) internal view returns(uint256[] memory rets, uint256 gas) { bytes memory fromHint; bytes memory destHint; { bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; (bool success, bytes memory data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildTokenToEthHint.selector, fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); fromHint = success ? abi.decode(data, (bytes)) : bytes(""); (success, data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildEthToTokenHint.selector, destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); destHint = success ? abi.decode(data, (bytes)) : bytes(""); } uint256 fromTokenDecimals = 10 ** IERC20(fromToken).universalDecimals(); uint256 destTokenDecimals = 10 ** IERC20(destToken).universalDecimals(); rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { if (i > 0 && rets[i - 1] == 0) { break; } rets[i] = amount.mul(i + 1).div(parts); if (!fromToken.isETH()) { if (fromHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( fromToken, ETH_ADDRESS, rets[i], flags, fromHint ); rets[i] = rate.mul(rets[i]).div(fromTokenDecimals); } if (!destToken.isETH() && rets[i] > 0) { if (destHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( ETH_ADDRESS, destToken, rets[i], flags.check(1 << 255) ? 10 : 0, destHint ); rets[i] = rate.mul(rets[i]).mul(destTokenDecimals).div(1e36); } } return (rets, 100_000); } function calculateBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorFinder.buildBancorPath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)( abi.encodeWithSelector( bancorNetwork.getReturnByPath.selector, path, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { (uint256 ret,) = abi.decode(data, (uint256,uint256)); rets[i] = ret; } } return (rets, path.length.mul(150_000)); } function calculateOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)( abi.encodeWithSelector( oasisExchange.getBuyAmount.selector, destToken.isETH() ? weth : destToken, fromToken.isETH() ? weth : fromToken, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { rets[i] = abi.decode(data, (uint256)); } } return (rets, 500_000); } function calculateMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IMooniswap mooniswap = mooniswapRegistry.target(); (bool success, bytes memory data) = address(mooniswap).staticcall.gas(1000000)( abi.encodeWithSelector( mooniswap.getReturn.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 1_000_000); } function calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswapV2( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function calculateUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, weth, destToken, amount, parts, flags ); } function calculateUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai || destToken == dai) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, dai, destToken, amount, parts, flags ); } function calculateUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == usdc || destToken == usdc) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, usdc, destToken, amount, parts, flags ); } function _calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 destTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal); if (exchange != IUniswapV2Exchange(0)) { uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange)); uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange)); for (uint i = 0; i < amounts.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]); } return (rets, 50_000); } } function _calculateUniswapV2OverMidToken( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); uint256 gas1; uint256 gas2; (rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags); (rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags); return (rets, gas1 + gas2); } function _calculateNoReturn( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { this; return (new uint256[](parts), 0); } } contract OneSplitBaseWrap is IOneSplit, OneSplitRoot { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) internal { if (fromToken == destToken) { return; } _swapFloor( fromToken, destToken, amount, distribution, flags ); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) internal; } contract OneSplit is IOneSplit, OneSplitRoot { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplitView) public { oneSplitView = _oneSplitView; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) public payable returns(uint256 returnAmount) { if (fromToken == destToken) { return amount; } function(IERC20,IERC20,uint256,uint256)[DEXES_COUNT] memory reserves = [ _swapOnUniswap, _swapOnNowhere, _swapOnBancor, _swapOnOasis, _swapOnCurveCompound, _swapOnCurveUSDT, _swapOnCurveY, _swapOnCurveBinance, _swapOnCurveSynthetix, _swapOnUniswapCompound, _swapOnUniswapChai, _swapOnUniswapAave, _swapOnMooniswap, _swapOnUniswapV2, _swapOnUniswapV2ETH, _swapOnUniswapV2DAI, _swapOnUniswapV2USDC, _swapOnCurvePAX, _swapOnCurveRenBTC, _swapOnCurveTBTC, _swapOnDforceSwap, _swapOnShell, _swapOnMStableMUSD, _swapOnCurveSBTC, _swapOnBalancer1, _swapOnBalancer2, _swapOnBalancer3, _swapOnKyber1, _swapOnKyber2, _swapOnKyber3, _swapOnKyber4 ]; require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size"); uint256 parts = 0; uint256 lastNonZeroIndex = 0; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { parts = parts.add(distribution[i]); lastNonZeroIndex = i; } } if (parts == 0) { if (fromToken.isETH()) { msg.sender.transfer(msg.value); return msg.value; } return amount; } fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); for (uint i = 0; i < distribution.length; i++) { if (distribution[i] == 0) { continue; } uint256 swapAmount = amount.mul(distribution[i]).div(parts); if (i == lastNonZeroIndex) { swapAmount = remainingAmount; } remainingAmount -= swapAmount; reserves[i](fromToken, destToken, swapAmount, flags); } returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: Return amount was not enough"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } // Swap helpers function _swapOnCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curveCompound), amount); curveCompound.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curveUSDT), amount); curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curveY), amount); curveY.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curveBinance), amount); curveBinance.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curveSynthetix), amount); curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { 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; } fromToken.universalApprove(address(curvePAX), amount); curvePAX.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(shell), amount); shell.swapByOrigin( address(fromToken), address(destToken), amount, 0, now + 50 ); } function _swapOnMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } function _swapOnCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveRenBTC), amount); curveRenBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == tbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == hbtc ? 3 : 0); int128 j = (destToken == tbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == hbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveTBTC), amount); curveTBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == sbtc ? 3 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == sbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveSBTC), amount); curveSBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(dforceSwap), amount); dforceSwap.swap(fromToken, destToken, amount); } function _swapOnUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { fromToken.universalApprove(address(fromExchange), returnAmount); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { ICompoundToken fromCompound = compoundRegistry.cTokenByToken(fromToken); fromToken.universalApprove(address(fromCompound), amount); fromCompound.mint(amount); _swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { ICompoundToken toCompound = compoundRegistry.cTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toCompound), amount, flags); toCompound.redeem(IERC20(toCompound).universalBalanceOf(address(this))); destToken.universalBalanceOf(address(this)); return; } } function _swapOnUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (fromToken == dai) { fromToken.universalApprove(address(chai), amount); chai.join(address(this), amount); _swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this)), flags); return; } if (destToken == dai) { _swapOnUniswap(fromToken, IERC20(chai), amount, flags); chai.exit(address(this), chai.balanceOf(address(this))); return; } } function _swapOnUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { IAaveToken fromAave = aaveRegistry.aTokenByToken(fromToken); fromToken.universalApprove(aave.core(), amount); aave.deposit(fromToken, amount, 1101); _swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { IAaveToken toAave = aaveRegistry.aTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toAave), amount, flags); toAave.redeem(toAave.balanceOf(address(this))); return; } } function _swapOnMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IMooniswap mooniswap = mooniswapRegistry.target(); fromToken.universalApprove(address(mooniswap), amount); mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0 ); } function _swapOnNowhere( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*flags*/ ) internal { revert("This source was deprecated"); } function _swapOnKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 ); } function _swapOnKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 ); } function _swapOnKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 ); } function _swapOnKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, _kyberReserveIdByTokens(fromToken, destToken) ); } function _swapOnKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags, bytes32 reserveId ) internal { uint256 returnAmount = amount; uint256 bps = flags.check(1 << 255) ? 10 : 0; bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; if (!fromToken.isETH()) { bytes memory fromHint = kyberHintHandler.buildTokenToEthHint( fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); fromToken.universalApprove(address(kyberNetworkProxy), amount); returnAmount = kyberNetworkProxy.tradeWithHintAndFee( fromToken, returnAmount, ETH_ADDRESS, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, bps, fromHint ); } if (!destToken.isETH()) { bytes memory destHint = kyberHintHandler.buildEthToTokenHint( destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); returnAmount = kyberNetworkProxy.tradeWithHintAndFee.value(returnAmount)( ETH_ADDRESS, returnAmount, destToken, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, bps, destHint ); } } function _swapOnBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorNetworkPathFinder.generatePath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); fromToken.universalApprove(address(bancorNetwork), amount); bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1); } function _swapOnOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 approveToken = fromToken.isETH() ? weth : fromToken; approveToken.universalApprove(address(oasisExchange), amount); oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 1 ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal); returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount); fromTokenReal.universalTransfer(address(exchange), amount); if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) { exchange.swap(0, returnAmount, address(this), ""); } else { exchange.swap(returnAmount, 0, address(this), ""); } if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( midToken, destToken, _swapOnUniswapV2Internal( fromToken, midToken, amount, flags ), flags ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( fromToken, destToken, amount, flags ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, weth, destToken, amount, flags ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, dai, destToken, amount, flags ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, usdc, destToken, amount, flags ); } function _swapOnBalancerX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/, uint256 poolIndex ) internal { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (fromToken.isETH()) { weth.deposit.value(amount)(); } (fromToken.isETH() ? weth : fromToken).universalApprove(pools[poolIndex], amount); IBalancerPool(pools[poolIndex]).swapExactAmountIn( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 0, uint256(-1) ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 0); } function _swapOnBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 1); } function _swapOnBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 2); } } // File: contracts/OneSplitCompound.sol pragma solidity ^0.5.0; contract OneSplitCompoundView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn( underlying, destToken, amount.mul(compoundRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18) ); return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitCompound is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compoundSwap( fromToken, destToken, amount, distribution, flags ); } function _compoundSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { ICompoundToken(address(fromToken)).redeem(amount); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return _compoundSwap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { cETH.mint.value(underlyingAmount)(); } else { underlying.universalApprove(address(destToken), underlyingAmount); ICompoundToken(address(destToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IFulcrum.sol pragma solidity ^0.5.0; contract IFulcrumToken is IERC20 { function tokenPrice() external view returns (uint256); function loanTokenAddress() external view returns (address); function mintWithEther(address receiver) external payable returns (uint256 mintAmount); function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount); function burnToEther(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); } // File: contracts/OneSplitFulcrum.sol pragma solidity ^0.5.0; contract OneSplitFulcrumBase { using UniversalERC20 for IERC20; function _isFulcrumToken(IERC20 token) internal view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature( "name()" )); if (!success) { return IERC20(-1); } bool foundBZX = false; for (uint i = 0; i + 6 < data.length; i++) { if (data[i + 0] == "F" && data[i + 1] == "u" && data[i + 2] == "l" && data[i + 3] == "c" && data[i + 4] == "r" && data[i + 5] == "u" && data[i + 6] == "m") { foundBZX = true; break; } } if (!foundBZX) { return IERC20(-1); } (success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( IFulcrumToken(address(token)).loanTokenAddress.selector )); if (!success) { return IERC20(-1); } return abi.decode(data, (IERC20)); } } contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn( underlying, destToken, amount.mul(fulcrumRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 381_000, distribution); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18) ); return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, destToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { if (underlying.isETH()) { IFulcrumToken(address(fromToken)).burnToEther(address(this), amount); } else { IFulcrumToken(address(fromToken)).burn(address(this), amount); } uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return super._swap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { underlying.universalApprove(address(destToken), underlyingAmount); IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, chai.chaiToDai(amount), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 197_000, distribution); } if (destToken == IERC20(chai)) { uint256 price = chai.chaiPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(1e18).div(price) ); return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } if (destToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(chai), daiBalance); chai.join(address(this), daiBalance); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IBdai.sol pragma solidity ^0.5.0; contract IBdai is IERC20 { function join(uint256) external; function exit(uint256) external; } // File: contracts/OneSplitBdai.sol pragma solidity ^0.5.0; contract OneSplitBdaiBase { IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 227_000, distribution); } if (destToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { bdai.exit(amount); uint256 btuBalance = btu.balanceOf(address(this)); if (btuBalance > 0) { (,uint256[] memory btuDistribution) = getExpectedReturn( btu, destToken, btuBalance, 1, flags ); _swap( btu, destToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, destToken, amount, distribution, flags ); } if (destToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(bdai), daiBalance); bdai.join(daiBalance); return; } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIearn.sol pragma solidity ^0.5.0; contract IIearn is IERC20 { function token() external view returns(IERC20); function calcPoolValueInToken() external view returns(uint256); function deposit(uint256 _amount) external; function withdraw(uint256 _shares) external; } // File: contracts/OneSplitIearn.sol pragma solidity ^0.5.0; contract OneSplitIearnBase { function _yTokens() internal pure returns(IIearn[13] memory) { return [ IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01), IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9), IIearn(0x73a052500105205d34Daf004eAb301916DA8190f), IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D), IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e), IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600), IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE), IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32), IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447), IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951), IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc), IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E), IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59) ]; } } contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _iearnGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { (returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn( yTokens[i].token(), destToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 260_000, distribution); } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; IERC20 token = yTokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()) ); return( returnAmount .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), estimateGasAmount + 743_000, distribution ); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, destToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(yTokens[i]), underlyingBalance); yTokens[i].deposit(underlyingBalance); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIdle.sol pragma solidity ^0.5.0; contract IIdle is IERC20 { function token() external view returns (IERC20); function tokenPrice() external view returns (uint256); function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts) external returns (uint256 mintedTokens); function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts) external returns (uint256 redeemedTokens); } // File: contracts/OneSplitIdle.sol pragma solidity ^0.5.0; contract OneSplitIdleBase { function _idleTokens() internal pure returns(IIdle[8] memory) { // https://developers.idle.finance/contracts-and-codebase return [ // V3 IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934), IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6), IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D), IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB), IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C), IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B), // V2 IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _idleGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { (returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn( tokens[i].token(), destToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 2_400_000, distribution); } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 _price = tokens[i].tokenPrice(); IERC20 token = tokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(_price).div(1e18) ); return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, destToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0)); _idleSwap(underlying, destToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(tokens[i]), underlyingBalance); tokens[i].mintIdleToken(underlyingBalance, new uint256[](0)); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/OneSplitAave.sol pragma solidity ^0.5.0; contract OneSplitAaveView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn( underlying, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 670_000, distribution); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 310_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitAave is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, destToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, destToken, amount, distribution, flags ); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); underlying.universalApprove(aave.core(), underlyingAmount); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice); } if (destToken == weth || destToken == bancorEtherToken) { return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, destToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (destToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (destToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitMStable.sol pragma solidity ^0.5.0; contract OneSplitMStableView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, destToken); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, dai); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, returnAmount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 300_000, distribution); } } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { (,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { IERC20 _destToken = destToken; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, dai, destTokenEthPriceTimesGasPrice ) ); (,, returnAmount) = musd_helper.getRedeemValidity(dai, returnAmount, destToken); return (returnAmount, estimateGasAmount + 300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMStable is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken); musd.redeem( destToken, result ); } else { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai); musd.redeem( dai, result ); super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } return; } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } else { super._swap( fromToken, dai, amount, distribution, flags ); musd.swap( dai, destToken, dai.balanceOf(address(this)), address(this) ); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IDMM.sol pragma solidity ^0.5.0; interface IDMMController { function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20); } contract IDMM is IERC20 { function getCurrentExchangeRate() public view returns(uint256); function mint(uint256 underlyingAmount) public returns(uint256); function redeem(uint256 amount) public returns(uint256); } // File: contracts/OneSplitDMM.sol pragma solidity ^0.5.0; contract OneSplitDMMBase { IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2); function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) { (bool success, bytes memory data) = address(_dmmController).staticcall( abi.encodeWithSelector( _dmmController.getUnderlyingTokenForDmm.selector, token ) ); if (!success || data.length == 0) { return IERC20(-1); } return abi.decode(data, (IERC20)); } function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) { (bool success, bytes memory data) = address(dmm).staticcall( abi.encodeWithSelector( dmm.getCurrentExchangeRate.selector ) ); if (!success || data.length == 0) { return 0; } return abi.decode(data, (uint256)); } } contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _dmmGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _dmmGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } IERC20 _fromToken = fromToken; (returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn( underlying, destToken, amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } uint256 price = _getDMMExchangeRate(IDMM(address(destToken))); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(price).div(1e18) ); return ( returnAmount.mul(1e18).div(price), estimateGasAmount + 430_000, distribution ); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _dmmSwap( fromToken, destToken, amount, distribution, flags ); } function _dmmSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IDMM(address(fromToken)).redeem(amount); uint256 balance = underlying.universalBalanceOf(address(this)); if (underlying == weth) { weth.withdraw(balance); } _dmmSwap( (underlying == weth) ? ETH_ADDRESS : underlying, destToken, balance, distribution, flags ); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, (underlying == weth) ? ETH_ADDRESS : underlying, amount, distribution, flags ); uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this)); if (underlying == weth) { weth.deposit.value(underlyingAmount); } underlying.universalApprove(address(destToken), underlyingAmount); IDMM(address(destToken)).mint(underlyingAmount); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMStableView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, OneSplitDMMView { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplit) public { oneSplitView = _oneSplit; } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWrap is OneSplitBaseWrap, OneSplitMStable, OneSplitChai, OneSplitBdai, OneSplitAave, OneSplitFulcrum, OneSplitCompound, OneSplitIearn, OneSplitIdle, OneSplitWeth, OneSplitDMM { IOneSplitView public oneSplitView; IOneSplit public oneSplit; constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public { oneSplitView = _oneSplitView; oneSplit = _oneSplit; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ) { uint256[] memory dist; returnAmounts = new uint256[](tokens.length - 1); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } IERC20[] memory _tokens = tokens; ( returnAmounts[i - 1], amount, dist ) = getExpectedReturnWithGas( _tokens[i - 1], _tokens[i], (i == 1) ? amount : returnAmounts[i - 2], parts[i], flags[i], destTokenEthPriceTimesGasPrices[i] ); estimateGasAmount = estimateGasAmount.add(amount); if (distribution.length == 0) { distribution = new uint256[](dist.length); } for (uint j = 0; j < distribution.length; j++) { distribution[j] = distribution[j].add(dist[j] << (8 * (i - 1))); } } } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount) { fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 confirmed = fromToken.universalBalanceOf(address(this)); _swap(fromToken, destToken, confirmed, distribution, flags); returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount) { tokens[0].universalTransferFrom(msg.sender, address(this), amount); returnAmount = tokens[0].universalBalanceOf(address(this)); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } uint256[] memory dist = new uint256[](distribution.length); for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (8 * (i - 1))) & 0xFF; } _swap( tokens[i - 1], tokens[i], returnAmount, dist, flags[i] ); returnAmount = tokens[i].universalBalanceOf(address(this)); tokens[i - 1].universalTransfer(msg.sender, tokens[i - 1].universalBalanceOf(address(this))); } require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); tokens[tokens.length - 1].universalTransfer(msg.sender, returnAmount); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { fromToken.universalApprove(address(oneSplit), amount); oneSplit.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0, distribution, flags ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IOneSplitView","name":"_oneSplit","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"getExpectedReturn","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"destTokenEthPriceTimesGasPrice","type":"uint256"}],"name":"getExpectedReturnWithGas","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplitView","outputs":[{"internalType":"contract IOneSplitView","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161323e38038061323e8339818101604052602081101561003357600080fd5b5051600080546001600160a01b039092166001600160a01b03199092169190911790556131d9806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063085e2c5b146100465780638373f265146100e3578063fbe4ed951461018d575b600080fd5b610088600480360360a081101561005c57600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356101b1565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100ce5781810151838201526020016100b6565b50505050905001935050505060405180910390f35b61012b600480360360c08110156100f957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356101d4565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561017757818101518382015260200161015f565b5050505090500194505050505060405180910390f35b610195610246565b604080516001600160a01b039092168252519081900360200190f35b600060606101c4878787878760006101d4565b9199919850909650505050505050565b6000806060876001600160a01b0316896001600160a01b031614156102255760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610233898989898989610255565b9250925092505b96509650969350505050565b6000546001600160a01b031681565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156102b55760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6102cb856508000000000063ffffffff61046616565b15156102e186634000000063ffffffff61046616565b151514156104585760006102f48a610472565b90506001600160a01b0380821614610395576001600160a01b03811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415610342575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b89610381828b610379670de0b6b3a764000061036d610360876105a8565b8f9063ffffffff61069716565b9063ffffffff6106f716565b8b8b8b610264565b91965062048058019450925061023a915050565b61039e89610472565b90506001600160a01b0380821614610456576001600160a01b03811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156103ec575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b60006103f78a6105a8565b90506104228b838b8b8b61041d670de0b6b3a764000061036d8e8a63ffffffff61069716565b610739565b919650945092506104458161036d87670de0b6b3a764000063ffffffff61069716565b94505062068fb0909201915061023a565b505b610233898989898989610739565b81811615155b92915050565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b602083106105005780518252601f1990920191602091820191016104e1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610560576040519150601f19603f3d011682016040523d82523d6000602084013e610565565b606091505b509150915081158061057657508051155b1561058757600019925050506105a3565b80806020019051602081101561059c57600080fd5b5051925050505b919050565b60408051600481526024810182526020810180516001600160e01b0316633ca967f360e01b1781529151815160009384936060936001600160a01b03881693919290918291908083835b602083106106115780518252601f1990920191602091820191016105f2565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610671576040519150601f19603f3d011682016040523d82523d6000602084013e610676565b606091505b509150915081158061068757508051155b15610587576000925050506105a3565b6000826106a65750600061046c565b828202828482816106b357fe5b04146106f05760405162461bcd60e51b81526004018080602001828103825260218152602001806131846021913960400191505060405180910390fd5b9392505050565b60006106f083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061074c565b60008060606102338989898989896107ee565b600081836107d85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561079d578181015183820152602001610785565b50505050905090810190601f1680156107ca5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816107e457fe5b0495945050505050565b6000806060876001600160a01b0316896001600160a01b0316141561083f5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610852856208000063ffffffff61046616565b151561086886634000000063ffffffff61046616565b15151415610957576001600160a01b03891673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214806108b757506001600160a01b03891673c0829421c1d260bd3cb3e0f06cfe2d52db2ce315145b156108e9576108de73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8989898989610961565b92509250925061023a565b6001600160a01b03881673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148061093057506001600160a01b03881673c0829421c1d260bd3cb3e0f06cfe2d52db2ce315145b15610957576108de8973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee89898989610961565b6102338989898989895b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156109c15760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6109d4856280000063ffffffff61046616565b156109e986634000000063ffffffff61046616565b151415610cfc576109f8613145565b610a00610d0a565b905060005b6008811015610b6657818160088110610a1a57fe5b60200201516001600160a01b03168b6001600160a01b03161415610b5e57610b4a828260088110610a4757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8457600080fd5b505afa158015610a98573d6000803e3d6000fd5b505050506040513d6020811015610aae57600080fd5b50518b610b42670de0b6b3a764000061036d878760088110610acc57fe5b60200201516001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b50518f9063ffffffff61069716565b8b8b8b610970565b91965062249f00019450925061023a915050565b600101610a05565b5060005b6008811015610cf957818160088110610b7f57fe5b60200201516001600160a01b03168a6001600160a01b03161415610cf157856000838360088110610bac57fe5b60200201516001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b158015610be957600080fd5b505afa158015610bfd573d6000803e3d6000fd5b505050506040513d6020811015610c1357600080fd5b505190506000848460088110610c2557fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c6257600080fd5b505afa158015610c76573d6000803e3d6000fd5b505050506040513d6020811015610c8c57600080fd5b50519050610cb98e828e8e8e610cb4670de0b6b3a764000061036d8b8b63ffffffff61069716565b610df0565b91995097509550610cdc8261036d8a670de0b6b3a764000063ffffffff61069716565b9750506213d620909501945061023a92505050565b600101610b6a565b50505b610233898989898989610df0565b610d12613145565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b03161415610e505760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610e628561080063ffffffff61046616565b15610e7786634000000063ffffffff61046616565b15141561130557610e86613164565b610e8e611313565b905060005b600d811015611027578181600d8110610ea857fe5b60200201516001600160a01b03168b6001600160a01b0316141561101f5761100b8282600d8110610ed557fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f1257600080fd5b505afa158015610f26573d6000803e3d6000fd5b505050506040513d6020811015610f3c57600080fd5b50518b6110038585600d8110610f4e57fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8b57600080fd5b505afa158015610f9f573d6000803e3d6000fd5b505050506040513d6020811015610fb557600080fd5b505161036d8787600d8110610fc657fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0957600080fd5b8b8b8b610dff565b9196506203f7a0019450925061023a915050565b600101610e93565b5060005b600d811015611302578181600d811061104057fe5b60200201516001600160a01b03168a6001600160a01b031614156112fa578560008383600d811061106d57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156110aa57600080fd5b505afa1580156110be573d6000803e3d6000fd5b505050506040513d60208110156110d457600080fd5b505190506111e28d828d8d8d6111dd8a8a600d81106110ef57fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561112c57600080fd5b505afa158015611140573d6000803e3d6000fd5b505050506040513d602081101561115657600080fd5b505161036d8c8c600d811061116757fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b1580156111a457600080fd5b505afa1580156111b8573d6000803e3d6000fd5b505050506040513d60208110156111ce57600080fd5b50518b9063ffffffff61069716565b611480565b919850965094506112e68484600d81106111f857fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b15801561123557600080fd5b505afa158015611249573d6000803e3d6000fd5b505050506040513d602081101561125f57600080fd5b505161036d8686600d811061127057fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d60208110156112d757600080fd5b50518a9063ffffffff61069716565b965050620b5658909401935061023a915050565b60010161102b565b50505b610233898989898989611480565b61131b613164565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156114e05760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6114f185601063ffffffff61046616565b151561150786634000000063ffffffff61046616565b151514156117a25760408051639bbde94760e01b81526001600160a01b038b166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d602081101561159757600080fd5b505190506001600160a01b0381161561163c5760008a6001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e557600080fd5b505afa1580156115f9573d6000803e3d6000fd5b505050506040513d602081101561160f57600080fd5b50519050610381828b611634670de0b6b3a764000061036d8e8763ffffffff61069716565b8b8b8b61148f565b60408051639bbde94760e01b81526001600160a01b038b166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b15801561169657600080fd5b505afa1580156116aa573d6000803e3d6000fd5b505050506040513d60208110156116c057600080fd5b505190506001600160a01b038116156117a057600085905060008a6001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561171357600080fd5b505afa158015611727573d6000803e3d6000fd5b505050506040513d602081101561173d57600080fd5b5051905061176a8c848c8c8c611765670de0b6b3a764000061036d8a8a63ffffffff61069716565b6117ac565b9197509550935061178d8161036d88670de0b6b3a764000063ffffffff61069716565b95505062068fb0909301925061023a9050565b505b6102338989898989895b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b0316141561180c5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61181d85602063ffffffff61046616565b151561183386634000000063ffffffff61046616565b151514156119e85760006118468a6119f6565b90506001600160a01b03808216146118fe5760008a6001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b15801561189357600080fd5b505afa1580156118a7573d6000803e3d6000fd5b505050506040513d60208110156118bd57600080fd5b505190506118ea828b6118e2670de0b6b3a764000061036d8e8763ffffffff61069716565b8b8b8b6117bb565b9196506205d048019450925061023a915050565b611907896119f6565b90506001600160a01b03808216146119e657600085905060008a6001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b15801561195957600080fd5b505afa15801561196d573d6000803e3d6000fd5b505050506040513d602081101561198357600080fd5b505190506119b08c848c8c8c6119ab670de0b6b3a764000061036d8a8a63ffffffff61069716565b611d6c565b919750955093506119d38161036d88670de0b6b3a764000063ffffffff61069716565b955050620566d0909301925061023a9050565b505b610233898989898989611d6c565b6000611a0a826001600160a01b0316611d7f565b15611a1857506000196105a3565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b60208310611a835780518252601f199092019160209182019101611a64565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114611ae4576040519150601f19603f3d011682016040523d82523d6000602084013e611ae9565b606091505b509150915081611aff57600019925050506105a3565b6000805b8251816006011015611c5857828160000181518110611b1e57fe5b6020910101516001600160f81b031916602360f91b148015611b615750828160010181518110611b4a57fe5b6020910101516001600160f81b031916607560f81b145b8015611b8e5750828160020181518110611b7757fe5b6020910101516001600160f81b031916601b60fa1b145b8015611bbb5750828160030181518110611ba457fe5b6020910101516001600160f81b031916606360f81b145b8015611be85750828160040181518110611bd157fe5b6020910101516001600160f81b031916603960f91b145b8015611c155750828160050181518110611bfe57fe5b6020910101516001600160f81b031916607560f81b145b8015611c425750828160060181518110611c2b57fe5b6020910101516001600160f81b031916606d60f81b145b15611c505760019150611c58565b600101611b03565b5080611c6b5760001993505050506105a3565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b60208310611cce5780518252601f199092019160209182019101611caf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114611d2f576040519150601f19603f3d011682016040523d82523d6000602084013e611d34565b606091505b50909350915082611d4c5760001993505050506105a3565b818060200190516020811015611d6157600080fd5b505195945050505050565b6000806060610233898989898989611db8565b60006001600160a01b038216158061046c57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b6000806060876001600160a01b0316896001600160a01b03161415611e095760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b611e1a85608063ffffffff61046616565b1515611e3086634000000063ffffffff61046616565b15151415611fae57604080516354732ba160e11b81526001600160a01b038b166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b158015611e9657600080fd5b505afa158015611eaa573d6000803e3d6000fd5b505050506040513d6020811015611ec057600080fd5b505190506001600160a01b03811615611ef457611ee1818a8a8a8a8a611db8565b919550620a3930019350915061023a9050565b604080516354732ba160e11b81526001600160a01b038b166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b158015611f4e57600080fd5b505afa158015611f62573d6000803e3d6000fd5b505050506040513d6020811015611f7857600080fd5b505190506001600160a01b03811615611fac57611f998a828a8a8a8a611fb8565b9195506204baf0019350915061023a9050565b505b6102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156120095760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61201b8561040063ffffffff61046616565b151561203186634000000063ffffffff61046616565b151514156120e9576001600160a01b038916736a4ffaafa8dd400676df8076ad6c724867b0e2e8141561209157612080736b175474e89094c44da98b954eedeac495271d0f89898989896120f3565b919450620376b8019250905061023a565b6001600160a01b038816736a4ffaafa8dd400676df8076ad6c724867b0e2e814156120e9576120d889736b175474e89094c44da98b954eedeac495271d0f898989896120f3565b91945062048058019250905061023a565b6102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156121445760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61215585604063ffffffff61046616565b151561216b86634000000063ffffffff61046616565b151514156122a4576001600160a01b0389167306af07097c9eeb7fd685c692751d5c66db49c21514156121ee576121dd736b175474e89094c44da98b954eedeac495271d0f896121d57306af07097c9eeb7fd685c692751d5c66db49c2158b63ffffffff6122b216565b8989896123ce565b91945062030188019250905061023a565b6001600160a01b0388167306af07097c9eeb7fd685c692751d5c66db49c21514156122a45760006122327306af07097c9eeb7fd685c692751d5c66db49c215612b38565b90506122718a736b175474e89094c44da98b954eedeac495271d0f8a8a8a61226c8761036d8d670de0b6b3a764000063ffffffff61069716565b6123ce565b91955093509150612294670de0b6b3a764000061036d868463ffffffff61069716565b935050620290409091019061023a565b6102338989898989896123ce565b60008073197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b03166320aba08b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561230257600080fd5b505afa158015612316573d6000803e3d6000fd5b505050506040513d602081101561232c57600080fd5b505142116123b25773197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663c92aecc46040518163ffffffff1660e01b815260040160206040518083038186803b15801561238157600080fd5b505afa158015612395573d6000803e3d6000fd5b505050506040513d60208110156123ab57600080fd5b50516123ba565b6123ba612b4c565b90506123c68184612cdb565b949350505050565b6000806060876001600160a01b0316896001600160a01b0316141561241f5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b612435856502000000000063ffffffff61046616565b151561244b86634000000063ffffffff61046616565b15151415612b2a576001600160a01b03891673e2f2a5c287993345a840db3b0845fbc70f5935a5141561284e576001600160a01b03881673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806124bf57506001600160a01b038816736b175474e89094c44da98b954eedeac495271d0f145b806124e657506001600160a01b03881673dac17f958d2ee523a2206206994597c13d831ec7145b8061250857506001600160a01b0388166e085d4780b73119b644ae5ecd22b376145b156126a35760408051633b3fb85360e21b81526001600160a01b038b81166004830152602482018a90528a1660448201529051734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808301926000929190829003018186803b15801561257657600080fd5b505afa15801561258a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260608110156125b357600080fd5b815160208301805160405192949293830192919084600160201b8211156125d957600080fd5b9083019060208201858111156125ee57600080fd5b8251600160201b81118282018810171561260757600080fd5b82525081516020918201929091019080838360005b8381101561263457818101518382015260200161261c565b50505050905090810190601f1680156126615780820380516001836020036101000a031916815260200191505b506040818152602092830151601f80845261040084019092529950899650620493e09550909350915082016103e080388339019050509194509250905061023a565b60408051633b3fb85360e21b81526001600160a01b038b16600482015260248101899052736b175474e89094c44da98b954eedeac495271d0f60448201529051734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808301926000929190829003018186803b15801561271e57600080fd5b505afa158015612732573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561275b57600080fd5b815160208301805160405192949293830192919084600160201b82111561278157600080fd5b90830190602082018581111561279657600080fd5b8251600160201b8111828201881017156127af57600080fd5b82525081516020918201929091019080838360005b838110156127dc5781810151838201526020016127c4565b50505050905090810190601f1680156128095780820380516001836020036101000a031916815260200191505b5060405260200151965061283d9350736b175474e89094c44da98b954eedeac495271d0f92508b9150869050898989612d03565b919450620493e0019250905061023a565b6001600160a01b03881673e2f2a5c287993345a840db3b0845fbc70f5935a51415612b2a576001600160a01b03891673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806128ba57506001600160a01b038916736b175474e89094c44da98b954eedeac495271d0f145b806128e157506001600160a01b03891673dac17f958d2ee523a2206206994597c13d831ec7145b8061290357506001600160a01b0389166e085d4780b73119b644ae5ecd22b376145b156129715760408051633975483b60e11b81526001600160a01b038b811660048301528a16602482015260448101899052905173e2f2a5c287993345a840db3b0845fbc70f5935a5916372ea9076916064808301926000929190829003018186803b15801561257657600080fd5b8761299e8a736b175474e89094c44da98b954eedeac495271d0f8a8a8a61299987858d612d16565b612d03565b60408051633b3fb85360e21b8152736b175474e89094c44da98b954eedeac495271d0f6004820152602481018590526001600160a01b038e16604482015290519397509195509350734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c91606480820192600092909190829003018186803b158015612a2257600080fd5b505afa158015612a36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015612a5f57600080fd5b815160208301805160405192949293830192919084600160201b821115612a8557600080fd5b908301906020820185811115612a9a57600080fd5b8251600160201b811182820188101715612ab357600080fd5b82525081516020918201929091019080838360005b83811015612ae0578181015183820152602001612ac8565b50505050905090810190601f168015612b0d5780820380516001836020036101000a031916815260200191505b5060405260200151975050620493e0909501945061023a92505050565b610233898989898989612d03565b600061046c82670de0b6b3a76400006122b2565b6000612cd6612c5873197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663487bf0826040518163ffffffff1660e01b815260040160206040518083038186803b158015612ba157600080fd5b505afa158015612bb5573d6000803e3d6000fd5b505050506040513d6020811015612bcb57600080fd5b5051604080516320aba08b60e01b8152905173197e90f9fad81970ba7976f33cbd77088e5d7cf7916320aba08b916004808301926020929190829003018186803b158015612c1857600080fd5b505afa158015612c2c573d6000803e3d6000fd5b505050506040513d6020811015612c4257600080fd5b505142036b033b2e3c9fd0803ce8000000612dbc565b73197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663c92aecc46040518163ffffffff1660e01b815260040160206040518083038186803b158015612ca557600080fd5b505afa158015612cb9573d6000803e3d6000fd5b505050506040513d6020811015612ccf57600080fd5b5051612cdb565b905090565b60006b033b2e3c9fd0803ce8000000612cf48484612e7b565b81612cfb57fe5b049392505050565b6000806060610233898989898989612e9f565b6000826001600160a01b0316846001600160a01b03161415612d395750806106f0565b6000612d6173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85662386f26fc10000612ff6565b90506000612d8b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87662386f26fc10000612ff6565b90508015612db057612da78161036d868563ffffffff61069716565b925050506106f0565b50600095945050505050565b6000838015612e5d57600184168015612dd757859250612ddb565b8392505b50600283046002850494505b8415612e57578586028687820414612dfe57600080fd5b81810181811015612e0e57600080fd5b85810497506002870615612e4a578785028589820414158915151615612e3357600080fd5b83810181811015612e4357600080fd5b8790049550505b5050600285049450612de7565b50612e73565b838015612e6d5760009250612e71565b8392505b505b509392505050565b6000811580612e9657505080820282828281612e9357fe5b04145b61046c57600080fd5b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015612f1257600080fd5b505afa158015612f26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015612f4f57600080fd5b81516020830151604080850180519151939592948301929184600160201b821115612f7957600080fd5b908301906020820185811115612f8e57600080fd5b82518660208202830111600160201b82111715612faa57600080fd5b82525081516020918201928201910280838360005b83811015612fd7578181015183820152602001612fbf565b5050505090500160405250505092509250925096509650969350505050565b60408051638373f26560e01b81526001600160a01b03858116600483015284166024820152604481018390526001606482015265c000200000016084820152600060a4820181905291513091638373f2659160c48083019286929190829003018186803b15801561306657600080fd5b505afa15801561307a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260608110156130a357600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156130cd57600080fd5b9083019060208201858111156130e257600080fd5b82518660208202830111600160201b821117156130fe57600080fd5b82525081516020918201928201910280838360005b8381101561312b578181015183820152602001613113565b505050509190910160405250949998505050505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a7231582017f9aa829287ce49383e16a8473afd667305abadafbeaffd2ba0ee43b0e2763764736f6c634300051100320000000000000000000000008fe17bfe7e0dc7c4691dcb84d25604f96c678f44
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063085e2c5b146100465780638373f265146100e3578063fbe4ed951461018d575b600080fd5b610088600480360360a081101561005c57600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356101b1565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100ce5781810151838201526020016100b6565b50505050905001935050505060405180910390f35b61012b600480360360c08110156100f957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356101d4565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561017757818101518382015260200161015f565b5050505090500194505050505060405180910390f35b610195610246565b604080516001600160a01b039092168252519081900360200190f35b600060606101c4878787878760006101d4565b9199919850909650505050505050565b6000806060876001600160a01b0316896001600160a01b031614156102255760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610233898989898989610255565b9250925092505b96509650969350505050565b6000546001600160a01b031681565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156102b55760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6102cb856508000000000063ffffffff61046616565b15156102e186634000000063ffffffff61046616565b151514156104585760006102f48a610472565b90506001600160a01b0380821614610395576001600160a01b03811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415610342575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b89610381828b610379670de0b6b3a764000061036d610360876105a8565b8f9063ffffffff61069716565b9063ffffffff6106f716565b8b8b8b610264565b91965062048058019450925061023a915050565b61039e89610472565b90506001600160a01b0380821614610456576001600160a01b03811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156103ec575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b60006103f78a6105a8565b90506104228b838b8b8b61041d670de0b6b3a764000061036d8e8a63ffffffff61069716565b610739565b919650945092506104458161036d87670de0b6b3a764000063ffffffff61069716565b94505062068fb0909201915061023a565b505b610233898989898989610739565b81811615155b92915050565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b602083106105005780518252601f1990920191602091820191016104e1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610560576040519150601f19603f3d011682016040523d82523d6000602084013e610565565b606091505b509150915081158061057657508051155b1561058757600019925050506105a3565b80806020019051602081101561059c57600080fd5b5051925050505b919050565b60408051600481526024810182526020810180516001600160e01b0316633ca967f360e01b1781529151815160009384936060936001600160a01b03881693919290918291908083835b602083106106115780518252601f1990920191602091820191016105f2565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610671576040519150601f19603f3d011682016040523d82523d6000602084013e610676565b606091505b509150915081158061068757508051155b15610587576000925050506105a3565b6000826106a65750600061046c565b828202828482816106b357fe5b04146106f05760405162461bcd60e51b81526004018080602001828103825260218152602001806131846021913960400191505060405180910390fd5b9392505050565b60006106f083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061074c565b60008060606102338989898989896107ee565b600081836107d85760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561079d578181015183820152602001610785565b50505050905090810190601f1680156107ca5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816107e457fe5b0495945050505050565b6000806060876001600160a01b0316896001600160a01b0316141561083f5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610852856208000063ffffffff61046616565b151561086886634000000063ffffffff61046616565b15151415610957576001600160a01b03891673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214806108b757506001600160a01b03891673c0829421c1d260bd3cb3e0f06cfe2d52db2ce315145b156108e9576108de73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8989898989610961565b92509250925061023a565b6001600160a01b03881673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148061093057506001600160a01b03881673c0829421c1d260bd3cb3e0f06cfe2d52db2ce315145b15610957576108de8973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee89898989610961565b6102338989898989895b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156109c15760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6109d4856280000063ffffffff61046616565b156109e986634000000063ffffffff61046616565b151415610cfc576109f8613145565b610a00610d0a565b905060005b6008811015610b6657818160088110610a1a57fe5b60200201516001600160a01b03168b6001600160a01b03161415610b5e57610b4a828260088110610a4757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8457600080fd5b505afa158015610a98573d6000803e3d6000fd5b505050506040513d6020811015610aae57600080fd5b50518b610b42670de0b6b3a764000061036d878760088110610acc57fe5b60200201516001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b50518f9063ffffffff61069716565b8b8b8b610970565b91965062249f00019450925061023a915050565b600101610a05565b5060005b6008811015610cf957818160088110610b7f57fe5b60200201516001600160a01b03168a6001600160a01b03161415610cf157856000838360088110610bac57fe5b60200201516001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b158015610be957600080fd5b505afa158015610bfd573d6000803e3d6000fd5b505050506040513d6020811015610c1357600080fd5b505190506000848460088110610c2557fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c6257600080fd5b505afa158015610c76573d6000803e3d6000fd5b505050506040513d6020811015610c8c57600080fd5b50519050610cb98e828e8e8e610cb4670de0b6b3a764000061036d8b8b63ffffffff61069716565b610df0565b91995097509550610cdc8261036d8a670de0b6b3a764000063ffffffff61069716565b9750506213d620909501945061023a92505050565b600101610b6a565b50505b610233898989898989610df0565b610d12613145565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b03161415610e505760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b610e628561080063ffffffff61046616565b15610e7786634000000063ffffffff61046616565b15141561130557610e86613164565b610e8e611313565b905060005b600d811015611027578181600d8110610ea857fe5b60200201516001600160a01b03168b6001600160a01b0316141561101f5761100b8282600d8110610ed557fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f1257600080fd5b505afa158015610f26573d6000803e3d6000fd5b505050506040513d6020811015610f3c57600080fd5b50518b6110038585600d8110610f4e57fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8b57600080fd5b505afa158015610f9f573d6000803e3d6000fd5b505050506040513d6020811015610fb557600080fd5b505161036d8787600d8110610fc657fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0957600080fd5b8b8b8b610dff565b9196506203f7a0019450925061023a915050565b600101610e93565b5060005b600d811015611302578181600d811061104057fe5b60200201516001600160a01b03168a6001600160a01b031614156112fa578560008383600d811061106d57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156110aa57600080fd5b505afa1580156110be573d6000803e3d6000fd5b505050506040513d60208110156110d457600080fd5b505190506111e28d828d8d8d6111dd8a8a600d81106110ef57fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561112c57600080fd5b505afa158015611140573d6000803e3d6000fd5b505050506040513d602081101561115657600080fd5b505161036d8c8c600d811061116757fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b1580156111a457600080fd5b505afa1580156111b8573d6000803e3d6000fd5b505050506040513d60208110156111ce57600080fd5b50518b9063ffffffff61069716565b611480565b919850965094506112e68484600d81106111f857fe5b60200201516001600160a01b0316637137ef996040518163ffffffff1660e01b815260040160206040518083038186803b15801561123557600080fd5b505afa158015611249573d6000803e3d6000fd5b505050506040513d602081101561125f57600080fd5b505161036d8686600d811061127057fe5b60200201516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ad57600080fd5b505afa1580156112c1573d6000803e3d6000fd5b505050506040513d60208110156112d757600080fd5b50518a9063ffffffff61069716565b965050620b5658909401935061023a915050565b60010161102b565b50505b610233898989898989611480565b61131b613164565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156114e05760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b6114f185601063ffffffff61046616565b151561150786634000000063ffffffff61046616565b151514156117a25760408051639bbde94760e01b81526001600160a01b038b166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b15801561156d57600080fd5b505afa158015611581573d6000803e3d6000fd5b505050506040513d602081101561159757600080fd5b505190506001600160a01b0381161561163c5760008a6001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e557600080fd5b505afa1580156115f9573d6000803e3d6000fd5b505050506040513d602081101561160f57600080fd5b50519050610381828b611634670de0b6b3a764000061036d8e8763ffffffff61069716565b8b8b8b61148f565b60408051639bbde94760e01b81526001600160a01b038b166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b15801561169657600080fd5b505afa1580156116aa573d6000803e3d6000fd5b505050506040513d60208110156116c057600080fd5b505190506001600160a01b038116156117a057600085905060008a6001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b15801561171357600080fd5b505afa158015611727573d6000803e3d6000fd5b505050506040513d602081101561173d57600080fd5b5051905061176a8c848c8c8c611765670de0b6b3a764000061036d8a8a63ffffffff61069716565b6117ac565b9197509550935061178d8161036d88670de0b6b3a764000063ffffffff61069716565b95505062068fb0909301925061023a9050565b505b6102338989898989895b60008060606102338989898989895b6000806060876001600160a01b0316896001600160a01b0316141561180c5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61181d85602063ffffffff61046616565b151561183386634000000063ffffffff61046616565b151514156119e85760006118468a6119f6565b90506001600160a01b03808216146118fe5760008a6001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b15801561189357600080fd5b505afa1580156118a7573d6000803e3d6000fd5b505050506040513d60208110156118bd57600080fd5b505190506118ea828b6118e2670de0b6b3a764000061036d8e8763ffffffff61069716565b8b8b8b6117bb565b9196506205d048019450925061023a915050565b611907896119f6565b90506001600160a01b03808216146119e657600085905060008a6001600160a01b0316637ff9b5966040518163ffffffff1660e01b815260040160206040518083038186803b15801561195957600080fd5b505afa15801561196d573d6000803e3d6000fd5b505050506040513d602081101561198357600080fd5b505190506119b08c848c8c8c6119ab670de0b6b3a764000061036d8a8a63ffffffff61069716565b611d6c565b919750955093506119d38161036d88670de0b6b3a764000063ffffffff61069716565b955050620566d0909301925061023a9050565b505b610233898989898989611d6c565b6000611a0a826001600160a01b0316611d7f565b15611a1857506000196105a3565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b60208310611a835780518252601f199092019160209182019101611a64565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114611ae4576040519150601f19603f3d011682016040523d82523d6000602084013e611ae9565b606091505b509150915081611aff57600019925050506105a3565b6000805b8251816006011015611c5857828160000181518110611b1e57fe5b6020910101516001600160f81b031916602360f91b148015611b615750828160010181518110611b4a57fe5b6020910101516001600160f81b031916607560f81b145b8015611b8e5750828160020181518110611b7757fe5b6020910101516001600160f81b031916601b60fa1b145b8015611bbb5750828160030181518110611ba457fe5b6020910101516001600160f81b031916606360f81b145b8015611be85750828160040181518110611bd157fe5b6020910101516001600160f81b031916603960f91b145b8015611c155750828160050181518110611bfe57fe5b6020910101516001600160f81b031916607560f81b145b8015611c425750828160060181518110611c2b57fe5b6020910101516001600160f81b031916606d60f81b145b15611c505760019150611c58565b600101611b03565b5080611c6b5760001993505050506105a3565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b60208310611cce5780518252601f199092019160209182019101611caf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114611d2f576040519150601f19603f3d011682016040523d82523d6000602084013e611d34565b606091505b50909350915082611d4c5760001993505050506105a3565b818060200190516020811015611d6157600080fd5b505195945050505050565b6000806060610233898989898989611db8565b60006001600160a01b038216158061046c57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b6000806060876001600160a01b0316896001600160a01b03161415611e095760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b611e1a85608063ffffffff61046616565b1515611e3086634000000063ffffffff61046616565b15151415611fae57604080516354732ba160e11b81526001600160a01b038b166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b158015611e9657600080fd5b505afa158015611eaa573d6000803e3d6000fd5b505050506040513d6020811015611ec057600080fd5b505190506001600160a01b03811615611ef457611ee1818a8a8a8a8a611db8565b919550620a3930019350915061023a9050565b604080516354732ba160e11b81526001600160a01b038b166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b158015611f4e57600080fd5b505afa158015611f62573d6000803e3d6000fd5b505050506040513d6020811015611f7857600080fd5b505190506001600160a01b03811615611fac57611f998a828a8a8a8a611fb8565b9195506204baf0019350915061023a9050565b505b6102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156120095760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61201b8561040063ffffffff61046616565b151561203186634000000063ffffffff61046616565b151514156120e9576001600160a01b038916736a4ffaafa8dd400676df8076ad6c724867b0e2e8141561209157612080736b175474e89094c44da98b954eedeac495271d0f89898989896120f3565b919450620376b8019250905061023a565b6001600160a01b038816736a4ffaafa8dd400676df8076ad6c724867b0e2e814156120e9576120d889736b175474e89094c44da98b954eedeac495271d0f898989896120f3565b91945062048058019250905061023a565b6102338989898989895b6000806060876001600160a01b0316896001600160a01b031614156121445760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b61215585604063ffffffff61046616565b151561216b86634000000063ffffffff61046616565b151514156122a4576001600160a01b0389167306af07097c9eeb7fd685c692751d5c66db49c21514156121ee576121dd736b175474e89094c44da98b954eedeac495271d0f896121d57306af07097c9eeb7fd685c692751d5c66db49c2158b63ffffffff6122b216565b8989896123ce565b91945062030188019250905061023a565b6001600160a01b0388167306af07097c9eeb7fd685c692751d5c66db49c21514156122a45760006122327306af07097c9eeb7fd685c692751d5c66db49c215612b38565b90506122718a736b175474e89094c44da98b954eedeac495271d0f8a8a8a61226c8761036d8d670de0b6b3a764000063ffffffff61069716565b6123ce565b91955093509150612294670de0b6b3a764000061036d868463ffffffff61069716565b935050620290409091019061023a565b6102338989898989896123ce565b60008073197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b03166320aba08b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561230257600080fd5b505afa158015612316573d6000803e3d6000fd5b505050506040513d602081101561232c57600080fd5b505142116123b25773197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663c92aecc46040518163ffffffff1660e01b815260040160206040518083038186803b15801561238157600080fd5b505afa158015612395573d6000803e3d6000fd5b505050506040513d60208110156123ab57600080fd5b50516123ba565b6123ba612b4c565b90506123c68184612cdb565b949350505050565b6000806060876001600160a01b0316896001600160a01b0316141561241f5760408051601f8082526104008201909252889160009190602082016103e080388339019050509194509250905061023a565b612435856502000000000063ffffffff61046616565b151561244b86634000000063ffffffff61046616565b15151415612b2a576001600160a01b03891673e2f2a5c287993345a840db3b0845fbc70f5935a5141561284e576001600160a01b03881673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806124bf57506001600160a01b038816736b175474e89094c44da98b954eedeac495271d0f145b806124e657506001600160a01b03881673dac17f958d2ee523a2206206994597c13d831ec7145b8061250857506001600160a01b0388166e085d4780b73119b644ae5ecd22b376145b156126a35760408051633b3fb85360e21b81526001600160a01b038b81166004830152602482018a90528a1660448201529051734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808301926000929190829003018186803b15801561257657600080fd5b505afa15801561258a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260608110156125b357600080fd5b815160208301805160405192949293830192919084600160201b8211156125d957600080fd5b9083019060208201858111156125ee57600080fd5b8251600160201b81118282018810171561260757600080fd5b82525081516020918201929091019080838360005b8381101561263457818101518382015260200161261c565b50505050905090810190601f1680156126615780820380516001836020036101000a031916815260200191505b506040818152602092830151601f80845261040084019092529950899650620493e09550909350915082016103e080388339019050509194509250905061023a565b60408051633b3fb85360e21b81526001600160a01b038b16600482015260248101899052736b175474e89094c44da98b954eedeac495271d0f60448201529051734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808301926000929190829003018186803b15801561271e57600080fd5b505afa158015612732573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561275b57600080fd5b815160208301805160405192949293830192919084600160201b82111561278157600080fd5b90830190602082018581111561279657600080fd5b8251600160201b8111828201881017156127af57600080fd5b82525081516020918201929091019080838360005b838110156127dc5781810151838201526020016127c4565b50505050905090810190601f1680156128095780820380516001836020036101000a031916815260200191505b5060405260200151965061283d9350736b175474e89094c44da98b954eedeac495271d0f92508b9150869050898989612d03565b919450620493e0019250905061023a565b6001600160a01b03881673e2f2a5c287993345a840db3b0845fbc70f5935a51415612b2a576001600160a01b03891673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806128ba57506001600160a01b038916736b175474e89094c44da98b954eedeac495271d0f145b806128e157506001600160a01b03891673dac17f958d2ee523a2206206994597c13d831ec7145b8061290357506001600160a01b0389166e085d4780b73119b644ae5ecd22b376145b156129715760408051633975483b60e11b81526001600160a01b038b811660048301528a16602482015260448101899052905173e2f2a5c287993345a840db3b0845fbc70f5935a5916372ea9076916064808301926000929190829003018186803b15801561257657600080fd5b8761299e8a736b175474e89094c44da98b954eedeac495271d0f8a8a8a61299987858d612d16565b612d03565b60408051633b3fb85360e21b8152736b175474e89094c44da98b954eedeac495271d0f6004820152602481018590526001600160a01b038e16604482015290519397509195509350734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c91606480820192600092909190829003018186803b158015612a2257600080fd5b505afa158015612a36573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015612a5f57600080fd5b815160208301805160405192949293830192919084600160201b821115612a8557600080fd5b908301906020820185811115612a9a57600080fd5b8251600160201b811182820188101715612ab357600080fd5b82525081516020918201929091019080838360005b83811015612ae0578181015183820152602001612ac8565b50505050905090810190601f168015612b0d5780820380516001836020036101000a031916815260200191505b5060405260200151975050620493e0909501945061023a92505050565b610233898989898989612d03565b600061046c82670de0b6b3a76400006122b2565b6000612cd6612c5873197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663487bf0826040518163ffffffff1660e01b815260040160206040518083038186803b158015612ba157600080fd5b505afa158015612bb5573d6000803e3d6000fd5b505050506040513d6020811015612bcb57600080fd5b5051604080516320aba08b60e01b8152905173197e90f9fad81970ba7976f33cbd77088e5d7cf7916320aba08b916004808301926020929190829003018186803b158015612c1857600080fd5b505afa158015612c2c573d6000803e3d6000fd5b505050506040513d6020811015612c4257600080fd5b505142036b033b2e3c9fd0803ce8000000612dbc565b73197e90f9fad81970ba7976f33cbd77088e5d7cf76001600160a01b031663c92aecc46040518163ffffffff1660e01b815260040160206040518083038186803b158015612ca557600080fd5b505afa158015612cb9573d6000803e3d6000fd5b505050506040513d6020811015612ccf57600080fd5b5051612cdb565b905090565b60006b033b2e3c9fd0803ce8000000612cf48484612e7b565b81612cfb57fe5b049392505050565b6000806060610233898989898989612e9f565b6000826001600160a01b0316846001600160a01b03161415612d395750806106f0565b6000612d6173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85662386f26fc10000612ff6565b90506000612d8b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87662386f26fc10000612ff6565b90508015612db057612da78161036d868563ffffffff61069716565b925050506106f0565b50600095945050505050565b6000838015612e5d57600184168015612dd757859250612ddb565b8392505b50600283046002850494505b8415612e57578586028687820414612dfe57600080fd5b81810181811015612e0e57600080fd5b85810497506002870615612e4a578785028589820414158915151615612e3357600080fd5b83810181811015612e4357600080fd5b8790049550505b5050600285049450612de7565b50612e73565b838015612e6d5760009250612e71565b8392505b505b509392505050565b6000811580612e9657505080820282828281612e9357fe5b04145b61046c57600080fd5b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015612f1257600080fd5b505afa158015612f26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015612f4f57600080fd5b81516020830151604080850180519151939592948301929184600160201b821115612f7957600080fd5b908301906020820185811115612f8e57600080fd5b82518660208202830111600160201b82111715612faa57600080fd5b82525081516020918201928201910280838360005b83811015612fd7578181015183820152602001612fbf565b5050505090500160405250505092509250925096509650969350505050565b60408051638373f26560e01b81526001600160a01b03858116600483015284166024820152604481018390526001606482015265c000200000016084820152600060a4820181905291513091638373f2659160c48083019286929190829003018186803b15801561306657600080fd5b505afa15801561307a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260608110156130a357600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156130cd57600080fd5b9083019060208201858111156130e257600080fd5b82518660208202830111600160201b821117156130fe57600080fd5b82525081516020918201928201910280838360005b8381101561312b578181015183820152602001613113565b505050509190910160405250949998505050505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a7231582017f9aa829287ce49383e16a8473afd667305abadafbeaffd2ba0ee43b0e2763764736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008fe17bfe7e0dc7c4691dcb84d25604f96c678f44
-----Decoded View---------------
Arg [0] : _oneSplit (address): 0x8fe17Bfe7E0dc7C4691DCb84D25604f96C678F44
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000008fe17bfe7e0dc7c4691dcb84d25604f96c678f44
Deployed Bytecode Sourcemap
182726:2382:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;182726:2382:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;183166:515;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;183166:515:0;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;183166:515:0;;;;;;;;;;;;;;;;;;183689:767;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;183689:767: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;183689:767:0;;;;;;;;;;;;;;;;;;;183029:33;;;:::i;:::-;;;;-1:-1:-1;;;;;183029:33:0;;;;;;;;;;;;;;183166:515;183388:20;183423:29;183513:160;183552:9;183576;183600:6;183621:5;183641;183661:1;183513:24;:160::i;:::-;183480:193;;;;-1:-1:-1;183166:515:0;;-1:-1:-1;;;;;;;183166:515:0:o;183689:767::-;184001:20;184036:25;184076:29;184150:9;-1:-1:-1;;;;;184137:22:0;:9;-1:-1:-1;;;;;184137:22:0;;184133:101;;;184195:26;;;48048:2;184195:26;;;;;;;;;184184:6;;184192:1;;184195:26;;;;17:15:-1;;105:10;184195:26:0;88:34:-1;136:17;;-1:-1;;184176:46:0;;-1:-1:-1;184176:46:0;-1:-1:-1;184176:46:0;-1:-1:-1;184176:46:0;;184133:101;184253:195;184298:9;184322;184346:6;184367:5;184387;184407:30;184253;:195::i;:::-;184246:202;;;;;;183689:767;;;;;;;;;;;:::o;183029:33::-;;;-1:-1:-1;;;;;183029:33:0;;:::o;177256:611::-;177534:20;177569:25;177609:29;177673:186;177709:9;177733;177757:6;177778:5;177798;177818:30;177875:2418;178151:20;178186:25;178226:29;178300:9;-1:-1:-1;;;;;178287:22:0;:9;-1:-1:-1;;;;;178287:22:0;;178283:101;;;178345:26;;;48048:2;178345:26;;;;;;;;;178334:6;;178342:1;;178345:26;;;;17:15:-1;;105:10;178345:26:0;88:34:-1;136:17;;-1:-1;;178326:46:0;;-1:-1:-1;178326:46:0;-1:-1:-1;178326:46:0;-1:-1:-1;178326:46:0;;178283:101;178446:29;:5;7796:13;178446:29;:11;:29;:::i;:::-;178400:75;;:42;:5;6679:10;178400:42;:11;:42;:::i;:::-;:75;;;178396:1675;;;178492:17;178512:33;178535:9;178512:22;:33::i;:::-;178492:53;-1:-1:-1;;;;;;178564:24:0;;;;178560:660;;-1:-1:-1;;;;;178613:18:0;;48315:42;178613:18;178609:91;;;-1:-1:-1;48103:42:0;178609:91;178738:9;178816:305;178860:10;178893:9;178925:68;178988:4;178925:58;178936:46;178738:9;178936:19;:46::i;:::-;178925:6;;:58;:10;:58;:::i;:::-;:62;:68;:62;:68;:::i;:::-;179016:5;179044;179072:30;178816:21;:305::i;:::-;178766:355;;-1:-1:-1;179182:7:0;179162:27;;-1:-1:-1;178766:355:0;-1:-1:-1;179140:64:0;;-1:-1:-1;;179140:64:0;178560:660;179249:33;179272:9;179249:22;:33::i;:::-;179236:46;-1:-1:-1;;;;;;179301:24:0;;;;179297:763;;-1:-1:-1;;;;;179350:18:0;;48315:42;179350:18;179346:91;;;-1:-1:-1;48103:42:0;179346:91;179455:13;179471:45;179504:9;179471:19;:45::i;:::-;179455:61;-1:-1:-1;179585:273:0;179638:9;179670:10;179703:6;179732:5;179760;179788:51;179834:4;179788:41;:30;179455:61;179788:41;:34;:41;:::i;:51::-;179585:30;:273::i;:::-;179535:323;;-1:-1:-1;179535:323:0;-1:-1:-1;179535:323:0;-1:-1:-1;179907:33:0;179934:5;179907:22;179535:323;179924:4;179907:22;:16;:22;:::i;:33::-;179877:167;-1:-1:-1;;179983:7:0;179963:27;;;;-1:-1:-1;179877:167:0;;179297:763;178396:1675;;180090:195;180135:9;180159;180183:6;180204:5;180224;180244:30;180090;:195::i;47598:117::-;47689:12;;;47688:19;;47598:117;;;;;:::o;176318:455::-;176490:128;;;-1:-1:-1;;;;;176490:128:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;176490:128:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;176441:188:0;;;;176386:6;;;;176420:17;;176266:42;;176490:128;;176441:188;;;;25:18:-1;176441:188: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;;;176441:188: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;;176405:224:0;;;;176647:7;176646:8;:28;;;-1:-1:-1;176658:11:0;;:16;176646:28;176642:78;;;-1:-1:-1;;176691:17:0;;;;;;176642:78;176750:4;176739:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;176739:26:0;;-1:-1:-1;;;176318:455:0;;;;:::o;176781:393::-;176936:91;;;22:32:-1;6:49;;176936:91:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;176898:140:0;;;;176842:7;;;;176877:17;;-1:-1:-1;;;;;176898:23:0;;;176936:91;;176898:140;;;;25:18:-1;176898:140: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;;;176898:140: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;;176862:176:0;;;;177056:7;177055:8;:28;;;-1:-1:-1;177067:11:0;;:16;177055:28;177051:69;;;177107:1;177100:8;;;;;;13623:471;13681:7;13926:6;13922:47;;-1:-1:-1;13956:1:0;13949:8;;13922:47;13993:5;;;13997:1;13993;:5;:1;14017:5;;;;;:10;14009:56;;;;-1:-1:-1;;;14009:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14085:1;13623:471;-1:-1:-1;;;13623:471:0:o;14562:132::-;14620:7;14647:39;14651:1;14654;14647:39;;;;;;;;;;;;;;;;;:3;:39::i;165805:612::-;166083:20;166118:25;166158:29;166222:187;166259:9;166283;166307:6;166328:5;166348;166368:30;166222:22;:187::i;15224:345::-;15310:7;15412:12;15405:5;15397:28;;;;-1:-1:-1;;;15397:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;15397:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15436:9;15452:1;15448;:5;;;;;;;15224:345;-1:-1:-1;;;;;15224:345:0:o;166425:1280::-;166702:20;166737:25;166777:29;166851:9;-1:-1:-1;;;;;166838:22:0;:9;-1:-1:-1;;;;;166838:22:0;;166834:101;;;166896:26;;;48048:2;166896:26;;;;;;;;;166885:6;;166893:1;;166896:26;;;;17:15:-1;;105:10;166896:26:0;88:34:-1;136:17;;-1:-1;;166877:46:0;;-1:-1:-1;166877:46:0;-1:-1:-1;166877:46:0;-1:-1:-1;166877:46:0;;166834:101;166997:30;:5;5708:7;166997:30;:11;:30;:::i;:::-;166951:76;;:42;:5;6679:10;166951:42;:11;:42;:::i;:::-;:76;;;166947:536;;;-1:-1:-1;;;;;167048:17:0;;48315:42;167048:17;;:50;;-1:-1:-1;;;;;;167069:29:0;;48228:42;167069:29;167048:50;167044:206;;;167126:108;48103:42;167170:9;167181:6;167189:5;167196;167203:30;167126;:108::i;:::-;167119:115;;;;;;;;167044:206;-1:-1:-1;;;;;167270:17:0;;48315:42;167270:17;;:50;;-1:-1:-1;;;;;;167291:29:0;;48228:42;167291:29;167270:50;167266:206;;;167348:108;167379:9;48103:42;167403:6;167411:5;167418;167425:30;167348;:108::i;167266:206::-;167502:195;167547:9;167571;167595:6;167616:5;167636;167656:30;155996:612;156274:20;156309:25;156349:29;156413:187;156450:9;156474;156498:6;156519:5;156539;156559:30;156616:2361;156894:20;156929:25;156969:29;157043:9;-1:-1:-1;;;;;157030:22:0;:9;-1:-1:-1;;;;;157030:22:0;;157026:101;;;157088:26;;;48048:2;157088:26;;;;;;;;;157077:6;;157085:1;;157088:26;;;;17:15:-1;;105:10;157088:26:0;88:34:-1;136:17;;-1:-1;;157069:46:0;;-1:-1:-1;157069:46:0;-1:-1:-1;157069:46:0;-1:-1:-1;157069:46:0;;157026:101;157191:30;:5;6177:8;157191:30;:11;:30;:::i;:::-;157190:31;157144:42;:5;6679:10;157144:42;:11;:42;:::i;:::-;157143:43;:78;157139:1616;;;157238:22;;:::i;:::-;157263:13;:11;:13::i;:::-;157238:38;-1:-1:-1;157298:6:0;157293:610;157314:13;157310:1;:17;157293:610;;;157377:6;157384:1;157377:9;;;;;;;;;;;-1:-1:-1;;;;;157357:30:0;:9;-1:-1:-1;;;;;157357:30:0;;157353:535;;;157462:317;157511:6;157518:1;157511:9;;;;;;;;;;;-1:-1:-1;;;;;157511:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;157511:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157511:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157511:17:0;157555:9;157591:44;157630:4;157591:34;157602:6;157609:1;157602:9;;;;;;;;;;;-1:-1:-1;;;;;157602:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;157602:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157602:22:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157602:22:0;157591:6;;:34;:10;:34;:::i;:44::-;157662:5;157694;157726:30;157462:22;:317::i;:::-;157412:367;;-1:-1:-1;157844:9:0;157824:29;;-1:-1:-1;157412:367:0;-1:-1:-1;157802:66:0;;-1:-1:-1;;157802:66:0;157353:535;157329:3;;157293:610;;;-1:-1:-1;157924:6:0;157919:825;157940:13;157936:1;:17;157919:825;;;158003:6;158010:1;158003:9;;;;;;;;;;;-1:-1:-1;;;;;157983:30:0;:9;-1:-1:-1;;;;;157983:30:0;;157979:750;;;158080:30;158038:39;158150:6;158157:1;158150:9;;;;;;;;;;;-1:-1:-1;;;;;158150:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;158150:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;158150:22:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;158150:22:0;;-1:-1:-1;158195:12:0;158210:6;158217:1;158210:9;;;;;;;;;;;-1:-1:-1;;;;;158210:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;158210:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;158210:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;158210:17:0;;-1:-1:-1;158300:298:0;158357:9;158210:17;158425:6;158458:5;158490;158522:53;158570:4;158522:43;:31;158558:6;158522:43;:35;:43;:::i;:53::-;158300:30;:298::i;:::-;158250:348;;-1:-1:-1;158250:348:0;-1:-1:-1;158250:348:0;-1:-1:-1;158629:34:0;158656:6;158629:22;158250:348;158646:4;158629:22;:16;:22;:::i;:34::-;158621:88;-1:-1:-1;;158685:9:0;158665:29;;;;-1:-1:-1;158621:88:0;;-1:-1:-1;;;158621:88:0;157979:750;157955:3;;157919:825;;;;157139:1616;;158774:195;158819:9;158843;158867:6;158888:5;158908;158928:30;158774;:195::i;155196:716::-;155241:15;;:::i;:::-;-1:-1:-1;155336:568:0;;;;;;;;155383:42;155336:568;;155447:42;155336:568;;;;155511:42;155336:568;;;;;;;155575:42;155336:568;;;;155639:42;155336:568;;;;155703:42;155336:568;;;;155786:42;155336:568;;;;155850:42;155336:568;;;;155196:716;:::o;149330:613::-;149608:20;149643:25;149683:29;149747:188;149785:9;149809;149833:6;149854:5;149874;149894:30;149951:2707;150229:20;150264:25;150304:29;150378:9;-1:-1:-1;;;;;150365:22:0;:9;-1:-1:-1;;;;;150365:22:0;;150361:101;;;150423:26;;;48048:2;150423:26;;;;;;;;;150412:6;;150420:1;;150423:26;;;;17:15:-1;;105:10;150423:26:0;88:34:-1;136:17;;-1:-1;;150404:46:0;;-1:-1:-1;150404:46:0;-1:-1:-1;150404:46:0;-1:-1:-1;150404:46:0;;150361:101;150526:31;:5;5080;150526:31;:11;:31;:::i;:::-;150525:32;150479:42;:5;6679:10;150479:42;:11;:42;:::i;:::-;150478:43;:79;150474:1962;;;150574:25;;:::i;:::-;150602:10;:8;:10::i;:::-;150574:38;-1:-1:-1;150634:6:0;150629:703;150650:14;150646:1;:18;150629:703;;;150714:7;150722:1;150714:10;;;;;;;;;;;-1:-1:-1;;;;;150694:31:0;:9;-1:-1:-1;;;;;150694:31:0;;150690:627;;;150800:410;150850:7;150858:1;150850:10;;;;;;;;;;;-1:-1:-1;;;;;150850:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;150850:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150850:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;150850:18:0;150895:9;150931:135;151041:7;151049:1;151041:10;;;;;;;;;;;-1:-1:-1;;;;;151041:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;151041:24:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151041:24:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;151041:24:0;150931:75;150972:7;150980:1;150972:10;;;;;;;;;;;-1:-1:-1;;;;;150972:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;150931:135:0;151093:5;151125;151157:30;150800:23;:410::i;:::-;150750:460;;-1:-1:-1;151275:7:0;151255:27;;-1:-1:-1;150750:460:0;-1:-1:-1;151233:64:0;;-1:-1:-1;;151233:64:0;150690:627;150666:3;;150629:703;;;-1:-1:-1;151353:6:0;151348:1077;151369:14;151365:1;:18;151348:1077;;;151433:7;151441:1;151433:10;;;;;;;;;;;-1:-1:-1;;;;;151413:31:0;:9;-1:-1:-1;;;;;151413:31:0;;151409:1001;;;151511:30;151469:39;151579:7;151587:1;151579:10;;;;;;;;;;;-1:-1:-1;;;;;151579:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;151579:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151579:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;151579:18:0;;-1:-1:-1;151670:405:0;151727:9;151579:18;151795:6;151828:5;151860;151892:160;152027:7;152035:1;152027:10;;;;;;;;;;;-1:-1:-1;;;;;152027:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152027:24:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152027:24:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;152027:24:0;151892:100;151958:7;151966:1;151958:10;;;;;;;;;;;-1:-1:-1;;;;;151958:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;151958:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151958:33:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;151958:33:0;151892:31;;:100;:65;:100;:::i;:160::-;151670:30;:405::i;:::-;151620:455;;-1:-1:-1;151620:455:0;-1:-1:-1;151620:455:0;-1:-1:-1;152133:141:0;152240:7;152248:1;152240:10;;;;;;;;;;;-1:-1:-1;;;;;152240:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152240:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152240:33:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;152240:33:0;152133:72;152180:7;152188:1;152180:10;;;;;;;;;;;-1:-1:-1;;;;;152180:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152180:24:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152180:24:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;152180:24:0;152133:12;;:72;:46;:72;:::i;:141::-;152100:290;-1:-1:-1;;152321:7:0;152301:27;;;;-1:-1:-1;152100:290:0;;-1:-1:-1;;152100:290:0;151409:1001;151385:3;;151348:1077;;;;150474:1962;;152455:195;152500:9;152524;152548:6;152569:5;152589;152609:30;152455;:195::i;148301:943::-;148343:17;;:::i;:::-;-1:-1:-1;148373:863:0;;;;;;;;148402:42;148373:863;;148467:42;148373:863;;;;148532:42;148373:863;;;;;;;148597:42;148373:863;;;;148662:42;148373:863;;;;148727:42;148373:863;;;;148792:42;148373:863;;;;148857:42;148373:863;;;;148922:42;148373:863;;;;148987:42;148373:863;;;;149052:42;148373:863;;;;149117:42;148373:863;;;;149182:42;148373:863;;;;148301:943;:::o;127723:616::-;128001:20;128036:25;128076:29;128140:191;128181:9;128205;128229:6;128250:5;128270;128290:30;128347:2335;128628:20;128663:25;128703:29;128777:9;-1:-1:-1;;;;;128764:22:0;:9;-1:-1:-1;;;;;128764:22:0;;128760:101;;;128822:26;;;48048:2;128822:26;;;;;;;;;128811:6;;128819:1;;128822:26;;;;17:15:-1;;105:10;128822:26:0;88:34:-1;136:17;;-1:-1;;128803:46:0;;-1:-1:-1;128803:46:0;-1:-1:-1;128803:46:0;-1:-1:-1;128803:46:0;;128760:101;128923:34;:5;4610:4;128923:34;:11;:34;:::i;:::-;128877:80;;:42;:5;6679:10;128877:42;:11;:42;:::i;:::-;:80;;;128873:1587;;;128994:66;;;-1:-1:-1;;;128994:66:0;;-1:-1:-1;;;;;128994:66:0;;;;;;;;128974:17;;52920:42;;128994:30;;:66;;;;;;;;;;;;;;;52920:42;128994:66;;;5:2:-1;;;;30:1;27;20:12;5:2;128994:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;128994:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;128994:66:0;;-1:-1:-1;;;;;;129079:23:0;;;129075:570;;129123:20;129169:9;-1:-1:-1;;;;;129146:53:0;;:55;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;129146:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129146:55:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129146:55:0;;-1:-1:-1;129270:276:0;129319:10;129352:9;129384:34;129413:4;129384:24;:6;129146:55;129384:24;:10;:24;:::i;:34::-;129441:5;129469;129497:30;129270:26;:276::i;129075:570::-;129674:66;;;-1:-1:-1;;;129674:66:0;;-1:-1:-1;;;;;129674:66:0;;;;;;;;52920:42;;129674:30;;:66;;;;;;;;;;;;;;52920:42;129674:66;;;5:2:-1;;;;30:1;27;20:12;5:2;129674:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129674:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129674:66:0;;-1:-1:-1;;;;;;129759:23:0;;;129755:694;;129803:39;129845:30;129803:72;;129894:20;129940:9;-1:-1:-1;;;;;129917:53:0;;:55;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;129917:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129917:55:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;129917:55:0;;-1:-1:-1;130041:281:0;130094:9;130126:10;130159:6;130188:5;130216;130244:59;130298:4;130244:49;:31;129917:55;130244:49;:35;:49;:::i;:59::-;130041:30;:281::i;:::-;129991:331;;-1:-1:-1;129991:331:0;-1:-1:-1;129991:331:0;-1:-1:-1;130349:40:0;130376:12;130349:22;129991:331;130366:4;130349:22;:16;:22;:::i;:40::-;130341:92;-1:-1:-1;;130411:7:0;130391:27;;;;-1:-1:-1;130341:92:0;;-1:-1:-1;130341:92:0;129755:694;128873:1587;;130479:195;130524:9;130548;130572:6;130593:5;130613;130633:30;135043:615;135321:20;135356:25;135396:29;135460:190;135500:9;135524;135548:6;135569:5;135589;135609:30;135666:2231;135946:20;135981:25;136021:29;136095:9;-1:-1:-1;;;;;136082:22:0;:9;-1:-1:-1;;;;;136082:22:0;;136078:101;;;136140:26;;;48048:2;136140:26;;;;;;;;;136129:6;;136137:1;;136140:26;;;;17:15:-1;;105:10;136140:26:0;88:34:-1;136:17;;-1:-1;;136121:46:0;;-1:-1:-1;136121:46:0;-1:-1:-1;136121:46:0;-1:-1:-1;136121:46:0;;136078:101;136241:33;:5;4670:4;136241:33;:11;:33;:::i;:::-;136195:79;;:42;:5;6679:10;136195:42;:11;:42;:::i;:::-;:79;;;136191:1484;;;136291:17;136311:26;136327:9;136311:15;:26::i;:::-;136291:46;-1:-1:-1;;;;;;136356:24:0;;;;136352:559;;136401:19;136445:9;-1:-1:-1;;;;;136423:44:0;;:46;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;136423:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;136423:46:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;136423:46:0;;-1:-1:-1;136538:274:0;136586:10;136619:9;136651:33;136679:4;136651:23;:6;136423:46;136651:23;:10;:23;:::i;:33::-;136707:5;136735;136763:30;136538:25;:274::i;:::-;136488:324;;-1:-1:-1;136873:7:0;136853:27;;-1:-1:-1;136488:324:0;-1:-1:-1;136831:64:0;;-1:-1:-1;;136831:64:0;136352:559;136940:26;136956:9;136940:15;:26::i;:::-;136927:39;-1:-1:-1;;;;;;136985:24:0;;;;136981:683;;137030:39;137072:30;137030:72;;137121:19;137165:9;-1:-1:-1;;;;;137143:44:0;;:46;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;137143:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;137143:46:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;137143:46:0;;-1:-1:-1;137258:280:0;137311:9;137343:10;137376:6;137405:5;137433;137461:58;137514:4;137461:48;:31;137143:46;137461:48;:35;:48;:::i;:58::-;137258:30;:280::i;:::-;137208:330;;-1:-1:-1;137208:330:0;-1:-1:-1;137208:330:0;-1:-1:-1;137565:39:0;137592:11;137565:22;137208:330;137582:4;137565:22;:16;:22;:::i;:39::-;137557:91;-1:-1:-1;;137626:7:0;137606:27;;;;-1:-1:-1;137557:91:0;;-1:-1:-1;137557:91:0;136981:683;136191:1484;;137694:195;137739:9;137763;137787:6;137808:5;137828;137848:30;137694;:195::i;133780:1173::-;133841:6;133864:13;:5;-1:-1:-1;;;;;133864:11:0;;:13::i;:::-;133860:63;;;-1:-1:-1;;;133894:17:0;;133860:63;134007:57;;;22:32:-1;6:49;;134007:57:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;133971:94:0;;;;133936:12;;133950:17;;-1:-1:-1;;;;;133971:25:0;;;134001:4;;134007:57;;133971:94;;;;25:18:-1;133971:94: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;;;133971:94: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;;133935:130:0;;;;134081:7;134076:58;;-1:-1:-1;;134105:17:0;;;;;;134076:58;134146:13;;134178:414;134203:4;:11;134195:1;134199;134195:5;:19;134178:414;;;134240:4;134245:1;134249;134245:5;134240:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134240:11:0;-1:-1:-1;;;134240:18:0;:57;;;;;134279:4;134284:1;134288;134284:5;134279:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134279:11:0;-1:-1:-1;;;134279:18:0;134240:57;:96;;;;;134318:4;134323:1;134327;134323:5;134318:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134318:11:0;-1:-1:-1;;;134318:18:0;134240:96;:135;;;;;134357:4;134362:1;134366;134362:5;134357:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134357:11:0;-1:-1:-1;;;134357:18:0;134240:135;:174;;;;;134396:4;134401:1;134405;134401:5;134396:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134396:11:0;-1:-1:-1;;;134396:18:0;134240:174;:213;;;;;134435:4;134440:1;134444;134440:5;134435:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134435:11:0;-1:-1:-1;;;134435:18:0;134240:213;:252;;;;;134474:4;134479:1;134483;134479:5;134474:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134474:11:0;-1:-1:-1;;;134474:18:0;134240:252;134236:345;;;134537:4;134526:15;;134560:5;;134236:345;134216:3;;134178:414;;;;134607:8;134602:59;;-1:-1:-1;;134632:17:0;;;;;;;134602:59;134727:103;;;22:32:-1;6:49;;134727:103:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;134691:140:0;;;;-1:-1:-1;;;;;134691:25:0;;;134721:4;;134727:103;134691:140;;;25:18:-1;134691:140: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;;;134691:140: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;-1:-1;134673:158:0;;-1:-1:-1;134673:158:0;-1:-1:-1;134673:158:0;134842:58;;-1:-1:-1;;134871:17:0;;;;;;;134842:58;134930:4;134919:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;134919:26:0;;133780:1173;-1:-1:-1;;;;;133780:1173:0:o;160952:646::-;161264:20;161299:25;161339:29;161403:187;161440:9;161464;161488:6;161509:5;161529;161549:30;161403:22;:187::i;40604:166::-;40655:4;-1:-1:-1;;;;;40680:39:0;;;;:81;;-1:-1:-1;;;;;;40723:38:0;;37776:42;40723:38;40672:90;40604:166;-1:-1:-1;;40604:166:0:o;161606:1937::-;161883:20;161918:25;161958:29;162032:9;-1:-1:-1;;;;;162019:22:0;:9;-1:-1:-1;;;;;162019:22:0;;162015:101;;;162077:26;;;48048:2;162077:26;;;;;;;;;162066:6;;162074:1;;162077:26;;;;17:15:-1;;105:10;162077:26:0;88:34:-1;136:17;;-1:-1;;162058:46:0;;-1:-1:-1;162058:46:0;-1:-1:-1;162058:46:0;-1:-1:-1;162058:46:0;;162015:101;162178:30;:5;4784:4;162178:30;:11;:30;:::i;:::-;162132:76;;:42;:5;6679:10;162132:42;:11;:42;:::i;:::-;:76;;;162128:1193;;;162245:58;;;-1:-1:-1;;;162245:58:0;;-1:-1:-1;;;;;162245:58:0;;;;;;;;162225:17;;53031:42;;162245:26;;:58;;;;;;;;;;;;;;;53031:42;162245:58;;;5:2:-1;;;;30:1;27;20:12;5:2;162245:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;162245:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;162245:58:0;;-1:-1:-1;;;;;;162322:23:0;;;162318:441;;162416:244;162461:10;162494:9;162526:6;162555:5;162583;162611:30;162416:22;:244::i;:::-;162366:294;;-1:-1:-1;162721:7:0;162701:27;;-1:-1:-1;162366:294:0;-1:-1:-1;162679:64:0;;-1:-1:-1;162679:64:0;162318:441;162788:58;;;-1:-1:-1;;;162788:58:0;;-1:-1:-1;;;;;162788:58:0;;;;;;;;53031:42;;162788:26;;:58;;;;;;;;;;;;;;53031:42;162788:58;;;5:2:-1;;;;30:1;27;20:12;5:2;162788:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;162788:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;162788:58:0;;-1:-1:-1;;;;;;162865:23:0;;;162861:449;;162959:252;163012:9;163044:10;163077:6;163106:5;163134;163162:30;162959;:252::i;:::-;162909:302;;-1:-1:-1;163272:7:0;163252:27;;-1:-1:-1;162909:302:0;-1:-1:-1;163230:64:0;;-1:-1:-1;163230:64:0;162861:449;162128:1193;;163340:195;163385:9;163409;163433:6;163454:5;163474;163494:30;144312:1757;144590:20;144625:25;144665:29;144739:9;-1:-1:-1;;;;;144726:22:0;:9;-1:-1:-1;;;;;144726:22:0;;144722:101;;;144784:26;;;48048:2;144784:26;;;;;;;;;144773:6;;144781:1;;144784:26;;;;17:15:-1;;105:10;144784:26:0;88:34:-1;136:17;;-1:-1;;144765:46:0;;-1:-1:-1;144765:46:0;-1:-1:-1;144765:46:0;-1:-1:-1;144765:46:0;;144722:101;144885:30;:5;5021;144885:30;:11;:30;:::i;:::-;144839:76;;:42;:5;6679:10;144839:42;:11;:42;:::i;:::-;:76;;;144835:1012;;;-1:-1:-1;;;;;144936:25:0;;144096:42;144936:25;144932:444;;;145032:245;48490:42;145111:9;145143:6;145172:5;145200;145228:30;145032;:245::i;:::-;144982:295;;-1:-1:-1;145338:7:0;145318:27;;-1:-1:-1;144982:295:0;-1:-1:-1;145296:64:0;;144932:444;-1:-1:-1;;;;;145396:25:0;;144096:42;145396:25;145392:444;;;145492:245;145545:9;48490:42;145603:6;145632:5;145660;145688:30;145492;:245::i;:::-;145442:295;;-1:-1:-1;145798:7:0;145778:27;;-1:-1:-1;145442:295:0;-1:-1:-1;145756:64:0;;145392:444;145866:195;145911:9;145935;145959:6;145980:5;146000;146020:30;140502:1866;140780:20;140815:25;140855:29;140929:9;-1:-1:-1;;;;;140916:22:0;:9;-1:-1:-1;;;;;140916:22:0;;140912:101;;;140974:26;;;48048:2;140974:26;;;;;;;;;140963:6;;140971:1;;140974:26;;;;17:15:-1;;105:10;140974:26:0;88:34:-1;136:17;;-1:-1;;140955:46:0;;-1:-1:-1;140955:46:0;-1:-1:-1;140955:46:0;-1:-1:-1;140955:46:0;;140912:101;141075:30;:5;4727:4;141075:30;:11;:30;:::i;:::-;141029:76;;:42;:5;6679:10;141029:42;:11;:42;:::i;:::-;:76;;;141025:1121;;;-1:-1:-1;;;;;141126:25:0;;48402:42;141126:25;141122:460;;;141222:261;48490:42;141301:9;141333:22;48402:42;141348:6;141333:22;:14;:22;:::i;:::-;141378:5;141406;141434:30;141222;:261::i;:::-;141172:311;;-1:-1:-1;141544:7:0;141524:27;;-1:-1:-1;141172:311:0;-1:-1:-1;141502:64:0;;141122:460;-1:-1:-1;;;;;141602:25:0;;48402:42;141602:25;141598:537;;;141648:13;141664:16;48402:42;141664:14;:16::i;:::-;141648:32;-1:-1:-1;141749:266:0;141802:9;48490:42;141860:6;141889:5;141917;141945:51;141648:32;141945:40;:30;141980:4;141945:40;:34;:40;:::i;:51::-;141749:30;:266::i;:::-;141699:316;;-1:-1:-1;141699:316:0;-1:-1:-1;141699:316:0;-1:-1:-1;142042:33:0;142070:4;142042:23;141699:316;142059:5;142042:23;:16;:23;:::i;:33::-;142034:85;-1:-1:-1;;142097:7:0;142077:27;;;;142034:85;;141598:537;142165:195;142210:9;142234;142258:6;142279:5;142299;142319:30;142165;:195::i;28061:218::-;28160:7;28180:11;25132:42;-1:-1:-1;;;;;28201:7:0;;:9;;;;;;;;;;;;;;;;;;;;;;8::-1;5:2;;;30:1;27;20:12;5:2;28201:9:0;;;;8::-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;28201:9:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28201:9:0;28195:3;:15;28194:41;;25132:42;-1:-1:-1;;;;;28226:7:0;;:9;;;;;;;;;;;;;;;;;;;;;;8::-1;5:2;;;30:1;27;20:12;5:2;28226:9:0;;;;8::-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;28226:9:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;28226:9:0;28194:41;;;28214:9;:7;:9::i;:::-;28180:55;;28253:18;28259:3;28264:6;28253:5;:18::i;:::-;28246:25;28061:218;-1:-1:-1;;;;28061:218:0:o;170214:2949::-;170492:20;170527:25;170567:29;170641:9;-1:-1:-1;;;;;170628:22:0;:9;-1:-1:-1;;;;;170628:22:0;;170624:101;;;170686:26;;;48048:2;170686:26;;;;;;;;;170675:6;;170683:1;;170686:26;;;;17:15:-1;;105:10;170686:26:0;88:34:-1;136:17;;-1:-1;;170667:46:0;;-1:-1:-1;170667:46:0;-1:-1:-1;170667:46:0;-1:-1:-1;170667:46:0;;170624:101;170787:38;:5;7659:13;170787:38;:11;:38;:::i;:::-;170741:84;;:42;:5;6679:10;170741:42;:11;:42;:::i;:::-;:84;;;170737:2204;;;-1:-1:-1;;;;;170846:25:0;;52304:42;170846:25;170842:931;;;-1:-1:-1;;;;;170896:17:0;;48579:42;170896:17;;:37;;-1:-1:-1;;;;;;170917:16:0;;48490:42;170917:16;170896:37;:58;;;-1:-1:-1;;;;;;170937:17:0;;48668:42;170937:17;170896:58;:79;;;-1:-1:-1;;;;;;170958:17:0;;48757:42;170958:17;170896:79;170892:866;;;171020:59;;;-1:-1:-1;;;171020:59:0;;-1:-1:-1;;;;;171020:59:0;;;;;;;;;;;;;;;;;;;;;52440:42;;171020:29;;:59;;;;;-1:-1:-1;;171020:59:0;;;;;;;52440:42;171020:59;;;5:2:-1;;;;30:1;27;20:12;5:2;171020:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;171020:59:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;171020:59:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;171020:59: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;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;171020:59:0;;420:4:-1;411:14;;;;171020:59:0;;;;;411:14:-1;171020:59: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;171020:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;171020:59:0;;;;;;;;;48048:2;171133:26;;;;;;;;;171020:59;-1:-1:-1;171020:59:0;;-1:-1:-1;171124:7:0;;-1:-1:-1;171020:59:0;;-1:-1:-1;48048:2:0;-1:-1:-1;171133:26:0;;17:15:-1;;105:10;171133:26:0;88:34:-1;136:17;;-1:-1;;171102:58:0;;-1:-1:-1;171102:58:0;-1:-1:-1;171102:58:0;-1:-1:-1;171102:58:0;;170892:866;171246:53;;;-1:-1:-1;;;171246:53:0;;-1:-1:-1;;;;;171246:53:0;;;;;;;;;;;;48490:42;171246:53;;;;;;52440:42;;171246:29;;:53;;;;;-1:-1:-1;;171246:53:0;;;;;;;52440:42;171246:53;;;5:2:-1;;;;30:1;27;20:12;5:2;171246:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;171246:53:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;171246:53:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;171246:53: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;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;171246:53:0;;420:4:-1;411:14;;;;171246:53:0;;;;;411:14:-1;171246:53: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;171246:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;171246:53:0;;;;;;-1:-1:-1;171372:279:0;;-1:-1:-1;48490:42:0;;-1:-1:-1;171459:9:0;;-1:-1:-1;171246:53:0;;-1:-1:-1;171534:5:0;171566;171598:30;171372;:279::i;:::-;171322:329;;-1:-1:-1;171716:7:0;171696:27;;-1:-1:-1;171322:329:0;-1:-1:-1;171674:64:0;;170892:866;-1:-1:-1;;;;;171793:25:0;;52304:42;171793:25;171789:1141;;;-1:-1:-1;;;;;171843:17:0;;48579:42;171843:17;;:37;;-1:-1:-1;;;;;;171864:16:0;;48490:42;171864:16;171843:37;:58;;;-1:-1:-1;;;;;;171884:17:0;;48668:42;171884:17;171843:58;:79;;;-1:-1:-1;;;;;;171905:17:0;;48757:42;171905:17;171843:79;171839:1076;;;171967:48;;;-1:-1:-1;;;171967:48:0;;-1:-1:-1;;;;;171967:48:0;;;;;;;;;;;;;;;;;;;;;52304:42;;171967:18;;:48;;;;;-1:-1:-1;;171967:48:0;;;;;;;52304:42;171967:48;;;5:2:-1;;;;30:1;27;20:12;171839:1076:0;172182:9;172264:442;172321:9;48490:42;172387:6;172420:5;172452;172484:199;172182:9;48490:42;172626:30;172484:36;:199::i;:::-;172264:30;:442::i;:::-;172749:59;;;-1:-1:-1;;;172749:59:0;;48490:42;172749:59;;;;;;;;;;-1:-1:-1;;;;;172749:59:0;;;;;;;;172214:492;;-1:-1:-1;172214:492:0;;-1:-1:-1;172214:492:0;-1:-1:-1;52440:42:0;;172749:29;;:59;;;;;-1:-1:-1;;172749:59:0;;;;;;;;52440:42;172749:59;;;5:2:-1;;;;30:1;27;20:12;5:2;172749:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;172749:59:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;172749:59:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;172749:59: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;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;172749:59:0;;420:4:-1;411:14;;;;172749:59:0;;;;;411:14:-1;172749:59: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;172749:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;172749:59:0;;;;;;-1:-1:-1;;172873:7:0;172853:27;;;;-1:-1:-1;172831:64:0;;-1:-1:-1;;;172831:64:0;171839:1076;172960:195;173005:9;173029;173053:6;173074:5;173094;173114:30;172960;:195::i;27718:109::-;27771:7;27798:21;27808:4;27814;27798:9;:21::i;27579:131::-;27620:7;27647:55;27653:37;25132:42;-1:-1:-1;;;;;27658:7:0;;:9;;;;;;;;;;;;;;;;;;;;;;8::-1;5:2;;;30:1;27;20:12;5:2;27658:9:0;;;;8::-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;27658:9:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27658:9:0;27675;;;-1:-1:-1;;;27675:9:0;;;;25132:42;;27675:7;;:9;;;;;27658;;27675;;;;;;;25132:42;27675:9;;;5:2:-1;;;;30:1;27;20:12;5:2;27675:9:0;;;;8::-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;27675:9:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27675:9:0;27669:3;:15;25213:6;27653:4;:37::i;:::-;25132:42;-1:-1:-1;;;;;27692:7:0;;:9;;;;;;;;;;;;;;;;;;;;;;8::-1;5:2;;;30:1;27;20:12;5:2;27692:9:0;;;;8::-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;27692:9:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27692:9:0;27647:5;:55::i;:::-;27640:62;;27579:131;:::o;25363:140::-;25422:9;25213:6;25479:10;25484:1;25487;25479:4;:10::i;:::-;:16;;;;;;;25363:140;-1:-1:-1;;;25363:140:0:o;58040:626::-;58318:20;58353:25;58393:29;58457:201;58508:9;58532;58556:6;58577:5;58597;58617:30;58457:36;:201::i;55854:573::-;56032:7;56069:9;-1:-1:-1;;;;;56056:22:0;:9;-1:-1:-1;;;;;56056:22:0;;56052:92;;;-1:-1:-1;56102:30:0;56095:37;;56052:92;56156:11;56170:50;48103:42;56198:9;56209:10;56170:14;:50::i;:::-;56156:64;;56231:11;56245:50;48103:42;56273:9;56284:10;56245:14;:50::i;:::-;56231:64;-1:-1:-1;56310:7:0;;56306:95;;56341:48;56385:3;56341:39;:30;56376:3;56341:39;:34;:39;:::i;:48::-;56334:55;;;;;;56306:95;-1:-1:-1;56418:1:0;;55854:573;-1:-1:-1;;;;;55854:573:0:o;25659:1912::-;25731:9;25849:1;25868:255;;;;26179:9;;;26214:74;;;;26358:1;26353:6;;26172:214;;26214:74;26257:4;26252:9;;26172:214;;26430:1;26424:4;26420:12;26514:1;26511;26507:9;26502:14;;26471:1063;26540:1;26471:1063;;;26651:1;26648;26644:9;26704:1;26700;26696:2;26692:10;26689:17;26679:2;;26749:1;26746;26739:12;26679:2;26827:4;26823:2;26819:13;26873:2;26864:7;26861:15;26858:2;;;26918:1;26915;26908:12;26858:2;26991:4;26982:7;26978:18;26973:23;;27032:1;27029;27025:9;27022:2;;;27083:1;27080;27076:9;27163:1;27159;27155:2;27151:10;27148:17;27141:25;27136:1;27129:9;27122:17;27118:49;27115:2;;;27213:1;27210;27203:12;27115:2;27299:4;27295:2;27291:13;27349:2;27340:7;27337:15;27334:2;;;27398:1;27395;27388:12;27334:2;27466:18;;;;-1:-1:-1;;27022:2:0;26607:927;;26581:1;26578;26574:9;26569:14;;26471:1063;;;26149:1404;25842:1711;;25868:255;25905:1;25932:74;;;;26076:1;26071:6;;25898:206;;25932:74;25975:4;25970:9;;25898:206;;25842:1711;;25827:1737;;;;;:::o;25228:127::-;25286:9;25316:6;;;:30;;-1:-1:-1;;25331:5:0;;;25345:1;25340;25331:5;25340:1;25326:15;;;;;:20;25316:30;25308:39;;;;;184464:641;184756:20;184895:12;;:202;;;-1:-1:-1;;;184895:202:0;;-1:-1:-1;;;;;184895:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;184756:20;;184831:29;;184895:12;;:37;;:202;;;;;184756:20;;184895:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;184895:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;184895:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;184895:202:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;184895:202: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;184895:202:0;;421:4:-1;412:14;;;;184895:202:0;;;;;412:14:-1;184895:202:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;184895:202:0;;;;;;;;;;;184888:209;;;;;;184464:641;;;;;;;;;;:::o;56435:505::-;56619:313;;;-1:-1:-1;;;56619:313:0;;-1:-1:-1;;;;;56619:313:0;;;;;;;;;;;;;;;;;;;56732:1;56619:313;;;;56748:157;56619:313;;;;56567:20;56619:313;;;;;;;;:4;;:29;;:313;;;;;56567:20;;56619:313;;;;;;;:4;:313;;;5:2:-1;;;;30:1;27;20:12;5:2;56619:313:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;56619:313:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;56619:313:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;56619:313: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;56619:313:0;;421:4:-1;412:14;;;;56619:313:0;;;;;412:14:-1;56619:313: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;;;;56619:313:0;;;;;;-1:-1:-1;56600:332:0;;56435:505;-1:-1:-1;;;;;;;;;56435:505:0:o;182726:2382::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;182726:2382:0;;;-1:-1:-1;;182726:2382:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;182726:2382:0;;;-1:-1:-1;;182726:2382:0:o
Swarm Source
bzzr://17f9aa829287ce49383e16a8473afd667305abadafbeaffd2ba0ee43b0e27637
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.