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 | 10398639 | 1498 days ago | IN | 0 ETH | 0.13523562 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
10730812 | 1447 days ago | 267.99483352 ETH | ||||
10730812 | 1447 days ago | 267.99483352 ETH | ||||
10688471 | 1453 days ago | 0.00000011 ETH | ||||
10688471 | 1453 days ago | 0.00000011 ETH | ||||
10614322 | 1465 days ago | 0.00000011 ETH | ||||
10614322 | 1465 days ago | 0.00000011 ETH | ||||
10614259 | 1465 days ago | 0.00000011 ETH | ||||
10614259 | 1465 days ago | 0.00000011 ETH | ||||
10580169 | 1470 days ago | 0.00000011 ETH | ||||
10580169 | 1470 days ago | 0.00000011 ETH | ||||
10580126 | 1470 days ago | 0.00000011 ETH | ||||
10580126 | 1470 days ago | 0.00000011 ETH | ||||
10573007 | 1471 days ago | 12.03410479 ETH | ||||
10573007 | 1471 days ago | 12.03410479 ETH | ||||
10562998 | 1472 days ago | 518.66275143 ETH | ||||
10562998 | 1472 days ago | 518.66275143 ETH | ||||
10530791 | 1477 days ago | 234.47818954 ETH | ||||
10530791 | 1477 days ago | 234.47818954 ETH | ||||
10529952 | 1478 days ago | 3.17187712 ETH | ||||
10529952 | 1478 days ago | 3.17187712 ETH | ||||
10529801 | 1478 days ago | 4.16344771 ETH | ||||
10529801 | 1478 days ago | 4.16344771 ETH | ||||
10455247 | 1489 days ago | 8.7599233 ETH | ||||
10455247 | 1489 days ago | 8.7599233 ETH | ||||
10455174 | 1489 days ago | 0.63123373 ETH |
Loading...
Loading
Contract Name:
OneSplitWrap
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-07-05 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/IOneSplit.sol pragma solidity ^0.5.0; // // [ msg.sender ] // | | // | | // \_/ // +---------------+ ________________________________ // | OneSplitAudit | _______________________________ \ // +---------------+ \ \ // | | ______________ | | (staticcall) // | | / ____________ \ | | // | | (call) / / \ \ | | // | | / / | | | | // \_/ | | \_/ \_/ // +--------------+ | | +----------------------+ // | OneSplitWrap | | | | OneSplitViewWrap | // +--------------+ | | +----------------------+ // | | | | | | // | | (delegatecall) | | (staticcall) | | (staticcall) // \_/ | | \_/ // +--------------+ | | +------------------+ // | OneSplit | | | | OneSplitView | // +--------------+ | | +------------------+ // | | / / // \ \________________/ / // \__________________/ // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_KYBER + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01; uint256 internal constant FLAG_DISABLE_KYBER = 0x02; uint256 internal constant FLAG_DISABLE_BANCOR = 0x04; uint256 internal constant FLAG_DISABLE_OASIS = 0x08; uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10; uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20; uint256 internal constant FLAG_DISABLE_CHAI = 0x40; uint256 internal constant FLAG_DISABLE_AAVE = 0x80; uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 internal constant FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Turned off by default uint256 internal constant FLAG_DISABLE_BDAI = 0x400; uint256 internal constant FLAG_DISABLE_IEARN = 0x800; uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 internal constant FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Turned off by default uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 internal constant FLAG_DISABLE_WETH = 0x80000; uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_IDLE = 0x800000; uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000; uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000; uint256 internal constant FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Turned off by default uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000; uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000; uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000; uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000; uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000; uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000; uint256 internal constant FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default uint256 internal constant FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Turned off by default } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/interface/IUniswapExchange.sol pragma solidity ^0.5.0; interface IUniswapExchange { function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought); function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought); function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256 tokensBought); function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); } // File: contracts/interface/IKyberNetworkContract.sol pragma solidity ^0.5.0; interface IKyberNetworkContract { function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless) external view returns (address reserve, uint256 rate); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity ^0.5.0; interface IKyberNetworkProxy { function getExpectedRate(IERC20 src, IERC20 dest, uint256 srcQty) external view returns (uint256 expectedRate, uint256 slippageRate); function tradeWithHint( IERC20 src, uint256 srcAmount, IERC20 dest, address destAddress, uint256 maxDestAmount, uint256 minConversionRate, address walletId, bytes calldata hint ) external payable returns (uint256); function kyberNetworkContract() external view returns (IKyberNetworkContract); // TODO: Limit usage by tx.gasPrice // function maxGasPrice() external view returns (uint256); // TODO: Limit usage by user cap // function getUserCapInWei(address user) external view returns (uint256); // function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256); } // File: contracts/interface/IKyberUniswapReserve.sol pragma solidity ^0.5.0; interface IKyberUniswapReserve { function uniswapFactory() external view returns (address); } // File: contracts/interface/IKyberOasisReserve.sol pragma solidity ^0.5.0; interface IKyberOasisReserve { function otc() external view returns (address); } // File: contracts/interface/IKyberBancorReserve.sol pragma solidity ^0.5.0; contract IKyberBancorReserve { function bancorEth() public view returns (address); } // File: contracts/interface/IBancorNetwork.sol pragma solidity ^0.5.0; interface IBancorNetwork { function getReturnByPath(address[] calldata path, uint256 amount) external view returns (uint256 returnAmount, uint256 conversionFee); function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn) external returns (uint256); function convert(address[] calldata path, uint256 amount, uint256 minReturn) external payable returns (uint256); } // File: contracts/interface/IBancorContractRegistry.sol pragma solidity ^0.5.0; contract IBancorContractRegistry { function addressOf(bytes32 contractName) external view returns (address); } // File: contracts/interface/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/IAaveToken.sol pragma solidity ^0.5.0; contract IAaveToken is IERC20 { function underlyingAssetAddress() external view returns (IERC20); function redeem(uint256 amount) external; } interface IAaveLendingPool { function core() external view returns (address); function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable; } // File: contracts/interface/IMooniswap.sol pragma solidity ^0.5.0; interface IMooniswapRegistry { function target() external view returns(IMooniswap); } interface IMooniswap { function getReturn( IERC20 fromToken, IERC20 destToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn ) external payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/UniversalERC20.sol pragma solidity ^0.5.0; library UniversalERC20 { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) { if (amount == 0) { return true; } if (isETH(token)) { address(uint160(to)).transfer(amount); } else { token.safeTransfer(to, amount); return true; } } function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()"); if (to != address(this)) { address(uint160(to)).transfer(amount); } if (msg.value > amount) { msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(from, to, amount); } } function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { if (msg.value > amount) { // Return remainder if exist msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(msg.sender, address(this), amount); } } function universalApprove(IERC20 token, address to, uint256 amount) internal { if (!isETH(token)) { if (amount == 0) { token.safeApprove(to, 0); return; } uint256 allowance = token.allowance(address(this), to); if (allowance < amount) { if (allowance > 0) { token.safeApprove(to, 0); } token.safeApprove(to, amount); } } } function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); } } function universalDecimals(IERC20 token) internal view returns (uint256) { if (isETH(token)) { return 18; } (bool success, bytes memory data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("decimals()") ); if (!success || data.length == 0) { (success, data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("DECIMALS()") ); } return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18; } function isETH(IERC20 token) internal pure returns(bool) { return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS)); } function notExist(IERC20 token) internal pure returns(bool) { return (address(token) == address(-1)); } } // File: contracts/interface/IUniswapV2Exchange.sol pragma solidity ^0.5.0; interface IUniswapV2Exchange { function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; } library UniswapV2ExchangeLib { using SafeMath for uint256; using UniversalERC20 for IERC20; function getReturn( IUniswapV2Exchange exchange, IERC20 fromToken, IERC20 destToken, uint amountIn ) internal view returns (uint256) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = destToken.universalBalanceOf(address(exchange)); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); return (denominator == 0) ? 0 : numerator.div(denominator); } } // File: contracts/interface/IUniswapV2Factory.sol pragma solidity ^0.5.0; interface IUniswapV2Factory { function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair); } // File: contracts/interface/IDForceSwap.sol pragma solidity ^0.5.0; interface IDForceSwap { function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256); function swap(IERC20 input, IERC20 output, uint256 amount) external; } // File: contracts/interface/IShell.sol pragma solidity ^0.5.0; interface IShell { function viewOriginTrade( address origin, address target, uint256 originAmount ) external view returns (uint256); function swapByOrigin( address origin, address target, uint256 originAmount, uint256 minTargetAmount, uint256 deadline ) external returns (uint256); } // File: contracts/interface/IMStable.sol pragma solidity ^0.5.0; contract IMStable is IERC20 { function getSwapOutput( IERC20 _input, IERC20 _output, uint256 _quantity ) external view returns (bool, string memory, uint256 output); function swap( IERC20 _input, IERC20 _output, uint256 _quantity, address _recipient ) external returns (uint256 output); function redeem( IERC20 _basset, uint256 _bassetQuantity ) external returns (uint256 massetRedeemed); } interface IMassetRedemptionValidator { function getRedeemValidity( IERC20 _mAsset, uint256 _mAssetQuantity, IERC20 _outputBasset ) external view returns (bool, string memory, uint256 output); } // File: contracts/interface/IBalancerRegistry.sol pragma solidity ^0.5.0; interface IBalancerPool { function swapExactAmountIn( IERC20 tokenIn, uint256 tokenAmountIn, IERC20 tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter); } pragma solidity ^0.5.0; interface IBalancerRegistry { event PoolAdded( address indexed pool ); event PoolTokenPairAdded( address indexed pool, address indexed fromToken, address indexed destToken ); event IndicesUpdated( address indexed fromToken, address indexed destToken, bytes32 oldIndices, bytes32 newIndices ); // Get info about pool pair for 1 SLOAD function getPairInfo(address pool, address fromToken, address destToken) external view returns(uint256 weight1, uint256 weight2, uint256 swapFee); // Pools function checkAddedPools(address pool) external view returns(bool); function getAddedPoolsLength() external view returns(uint256); function getAddedPools() external view returns(address[] memory); function getAddedPoolsWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Tokens function getAllTokensLength() external view returns(uint256); function getAllTokens() external view returns(address[] memory); function getAllTokensWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Pairs function getPoolsLength(address fromToken, address destToken) external view returns(uint256); function getPools(address fromToken, address destToken) external view returns(address[] memory); function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit) external view returns(address[] memory result); function getBestPools(address fromToken, address destToken) external view returns(address[] memory pools); function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit) external view returns(address[] memory pools); // Get swap rates function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount) external view returns(uint256); function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts) external view returns(uint256[] memory result); // Add and update registry function addPool(address pool) external returns(uint256 listed); function addPools(address[] calldata pools) external returns(uint256[] memory listed); function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external; } // File: contracts/OneSplitBase.sol pragma solidity ^0.5.0; contract IOneSplitView is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns(bool) { return (flags & flag) != 0; } } contract OneSplitRoot is IOneSplitView { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20; using UniversalERC20 for IWETH; using UniswapV2ExchangeLib for IUniswapV2Exchange; using ChaiHelper for IChai; uint256 constant internal DEXES_COUNT = 27; IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant internal bnt = IERC20(0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C); IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D); IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847); IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380); IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6); IERC20 constant internal comp = IERC20(0xc00e94Cb662C3520282E6f5717214004A7f26888); IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x818E6FECD516Ecc3849DAf6845e3EC868087B755); IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); //IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); 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); 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 _getCompoundToken(IERC20 token) internal pure returns(ICompoundToken) { if (token.isETH()) { // ETH return ICompoundToken(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); } if (token == IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { // DAI return ICompoundToken(0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643); } if (token == IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF)) { // BAT return ICompoundToken(0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E); } if (token == IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862)) { // REP return ICompoundToken(0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1); } if (token == IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { // USDC return ICompoundToken(0x39AA39c021dfbaE8faC545936693aC917d5E7563); } if (token == IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)) { // WBTC return ICompoundToken(0xC11b1268C1A384e55C48c2391d8d480264A3A7F4); } if (token == IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498)) { // ZRX return ICompoundToken(0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407); } if (token == IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { // USDT return ICompoundToken(0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9); } return ICompoundToken(0); } function _getAaveToken(IERC20 token) internal pure returns(IAaveToken) { if (token.isETH()) { // ETH return IAaveToken(0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04); } if (token == IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F)) { // DAI return IAaveToken(0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d); } if (token == IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48)) { // USDC return IAaveToken(0x9bA00D6856a4eDF4665BcA2C2309936572473B7E); } if (token == IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51)) { // SUSD return IAaveToken(0x625aE63000f46200499120B906716420bd059240); } if (token == IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53)) { // BUSD return IAaveToken(0x6Ee0f7BB50a54AB5253dA0667B0Dc2ee526C30a8); } if (token == IERC20(0x0000000000085d4780B73119b644AE5ecd22b376)) { // TUSD return IAaveToken(0x4DA9b813057D04BAef4e5800E36083717b4a0341); } if (token == IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7)) { // USDT return IAaveToken(0x71fc860F7D3A592A4a98740e39dB31d25db65ae8); } if (token == IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF)) { // BAT return IAaveToken(0xE1BA0FB44CCb0D11b80F92f4f8Ed94CA3fF51D00); } if (token == IERC20(0xdd974D5C2e2928deA5F71b9825b8b646686BD200)) { // KNC return IAaveToken(0x9D91BE44C06d373a8a226E1f3b146956083803eB); } if (token == IERC20(0x80fB784B7eD66730e8b1DBd9820aFD29931aab03)) { // LEND return IAaveToken(0x7D2D3688Df45Ce7C552E19c27e007673da9204B8); } if (token == IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA)) { // LINK return IAaveToken(0xA64BD6C70Cb9051F6A9ba1F163Fdc07E0DfB5F84); } if (token == IERC20(0x0F5D2fB29fb7d3CFeE444a200298f468908cC942)) { // MANA return IAaveToken(0x6FCE4A401B6B80ACe52baAefE4421Bd188e76F6f); } if (token == IERC20(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2)) { // MKR return IAaveToken(0x7deB5e830be29F91E298ba5FF1356BB7f8146998); } if (token == IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862)) { // REP return IAaveToken(0x71010A9D003445aC60C4e6A7017c1E89A477B438); } if (token == IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F)) { // SNX return IAaveToken(0x328C4c80BC7aCa0834Db37e6600A6c49E12Da4DE); } if (token == IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599)) { // WBTC return IAaveToken(0xFC4B8ED459e00e5400be803A9BB3954234FD50e3); } if (token == IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498)) { // ZRX return IAaveToken(0x6Fb0855c404E09c47C3fBCA25f08d4E41f9F062f); } return IAaveToken(0); } function _scaleDestTokenEthPriceTimesGasPrice( IERC20 fromToken, IERC20 destToken, uint256 destTokenEthPriceTimesGasPrice ) internal view returns(uint256) { 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" ]; for (uint i = 0; i < DEXES_COUNT; i++) { if (args.distribution[i] > 0) { if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add(uint256( (value == VERY_NEGATIVE_VALUE ? 0 : value) + int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18)) )); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves(uint256 flags) internal pure returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory) { bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); return [ invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap, invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC, invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap, invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell, invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3 ]; } function _calculateNoGas( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*parts*/, uint256 /*destTokenEthPriceTimesGasPrice*/, uint256 /*flags*/, uint256 /*destTokenEthPrice*/ ) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) { this; } // View Helpers function _calculateBalancer( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/, uint256 poolIndex ) internal view returns(uint256[] memory rets, uint256 gas) { 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 = _getCompoundToken(midPreToken); if (midToken != ICompoundToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, midToken.exchangeRateStored(), flags, 200_000, 200_000 ); } } return (new uint256[](parts), 0); } function calculateUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai && destToken.isETH() || fromToken.isETH() && destToken == dai) { return _calculateUniswapWrapped( fromToken, chai, destToken, amount, parts, chai.chaiPrice(), flags, 180_000, 160_000 ); } return (new uint256[](parts), 0); } function calculateUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { IAaveToken midToken = _getAaveToken(midPreToken); if (midToken != IAaveToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, 1e18, flags, 310_000, 670_000 ); } } return (new uint256[](parts), 0); } function _calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal view returns(uint256 returnAmount, uint256 gas) { (bool success, bytes memory data) = address(kyberNetworkProxy).staticcall.gas(2300)(abi.encodeWithSelector( kyberNetworkProxy.kyberNetworkContract.selector )); if (!success || data.length == 0) { return (0, 0); } IKyberNetworkContract kyberNetworkContract = IKyberNetworkContract(abi.decode(data, (address))); if (fromToken.isETH() || destToken.isETH()) { return _calculateKyberWithEth(kyberNetworkContract, fromToken, destToken, amount, flags); } (uint256 value, uint256 gasFee) = _calculateKyberWithEth(kyberNetworkContract, fromToken, ETH_ADDRESS, amount, flags); if (value == 0) { return (0, 0); } (uint256 value2, uint256 gasFee2) = _calculateKyberWithEth(kyberNetworkContract, ETH_ADDRESS, destToken, value, flags); return (value2, gasFee + gasFee2); } function _calculateKyberWithEth( IKyberNetworkContract kyberNetworkContract, IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal view returns(uint256 returnAmount, uint256 gas) { require(fromToken.isETH() || destToken.isETH(), "2ETH"); (bool success, bytes memory data) = address(kyberNetworkContract).staticcall.gas(1500000)(abi.encodeWithSelector( kyberNetworkContract.searchBestRate.selector, fromToken.isETH() ? ETH_ADDRESS : fromToken, destToken.isETH() ? ETH_ADDRESS : destToken, amount, true )); if (!success) { return (0, 0); } (address reserve, uint256 ret) = abi.decode(data, (address,uint256)); if (ret == 0) { return (0, 0); } if ((reserve == 0x31E085Afd48a1d6e51Cc193153d625e8f0514C7F && !flags.check(FLAG_ENABLE_KYBER_UNISWAP_RESERVE)) || (reserve == 0x1E158c0e93c30d24e918Ef83d1e0bE23595C3c0f && !flags.check(FLAG_ENABLE_KYBER_OASIS_RESERVE)) || (reserve == 0x053AA84FCC676113a57e0EbB0bD1913839874bE4 && !flags.check(FLAG_ENABLE_KYBER_BANCOR_RESERVE))) { return (0, 0); } if (!flags.check(FLAG_ENABLE_KYBER_UNISWAP_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberUniswapReserve(reserve).uniswapFactory.selector )); if (success) { return (0, 0); } } if (!flags.check(FLAG_ENABLE_KYBER_OASIS_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberOasisReserve(reserve).otc.selector )); if (success) { return (0, 0); } } if (!flags.check(FLAG_ENABLE_KYBER_BANCOR_RESERVE)) { (success,) = reserve.staticcall.gas(2300)(abi.encodeWithSelector( IKyberBancorReserve(reserve).bancorEth.selector )); if (success) { return (0, 0); } } return ( ret.mul(amount) .mul(10 ** IERC20(destToken).universalDecimals()) .div(10 ** IERC20(fromToken).universalDecimals()) .div(1e18), 700_000 ); } function calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { (rets[i], gas) = _calculateKyber(fromToken, destToken, amount.mul(i + 1).div(parts), flags); if (rets[i] == 0) { break; } } return (rets, gas); } function calculateBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = 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) returns(uint256)[DEXES_COUNT] memory reserves = [ _swapOnUniswap, _swapOnKyber, _swapOnBancor, _swapOnOasis, _swapOnCurveCompound, _swapOnCurveUSDT, _swapOnCurveY, _swapOnCurveBinance, _swapOnCurveSynthetix, _swapOnUniswapCompound, _swapOnUniswapChai, _swapOnUniswapAave, _swapOnMooniswap, _swapOnUniswapV2, _swapOnUniswapV2ETH, _swapOnUniswapV2DAI, _swapOnUniswapV2USDC, _swapOnCurvePAX, _swapOnCurveRenBTC, _swapOnCurveTBTC, _swapOnDforceSwap, _swapOnShell, _swapOnMStableMUSD, _swapOnCurveSBTC, _swapOnBalancer1, _swapOnBalancer2, _swapOnBalancer3 ]; require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size"); uint256 parts = 0; uint256 lastNonZeroIndex = 0; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { parts = parts.add(distribution[i]); lastNonZeroIndex = i; } } if (parts == 0) { if (fromToken.isETH()) { msg.sender.transfer(msg.value); return msg.value; } return amount; } fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); for (uint i = 0; i < distribution.length; i++) { if (distribution[i] == 0) { continue; } uint256 swapAmount = amount.mul(distribution[i]).div(parts); if (i == lastNonZeroIndex) { swapAmount = remainingAmount; } remainingAmount -= swapAmount; reserves[i](fromToken, destToken, swapAmount); } returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: Return amount was not enough"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } // Swap helpers function _swapOnCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveCompound), amount); curveCompound.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveUSDT), amount); curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == tusd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == tusd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveY), amount); curveY.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == busd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == busd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveBinance), amount); curveBinance.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == susd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == susd ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveSynthetix), amount); curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == pax ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == pax ? 4 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curvePAX), amount); curvePAX.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnShell( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns (uint256) { fromToken.universalApprove(address(shell), amount); return shell.swapByOrigin( address(fromToken), address(destToken), amount, 0, now + 50 ); } function _swapOnMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns (uint256) { fromToken.universalApprove(address(musd), amount); return musd.swap( fromToken, destToken, amount, address(this) ); } function _swapOnCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveRenBTC), amount); curveRenBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == tbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == hbtc ? 3 : 0); int128 j = (destToken == tbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == hbtc ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveTBTC), amount); curveTBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == sbtc ? 3 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == sbtc ? 3 : 0); if (i == 0 || j == 0) { return 0; } fromToken.universalApprove(address(curveSBTC), amount); curveSBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { fromToken.universalApprove(address(dforceSwap), amount); dforceSwap.swap(fromToken, destToken, amount); } function _swapOnUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { fromToken.universalApprove(address(fromExchange), returnAmount); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } return returnAmount; } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { ICompoundToken fromCompound = _getCompoundToken(fromToken); fromToken.universalApprove(address(fromCompound), amount); fromCompound.mint(amount); return _swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this))); } if (!destToken.isETH()) { ICompoundToken toCompound = _getCompoundToken(destToken); uint256 compoundAmount = _swapOnUniswap(fromToken, IERC20(toCompound), amount); toCompound.redeem(compoundAmount); return destToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (fromToken == dai) { fromToken.universalApprove(address(chai), amount); chai.join(address(this), amount); return _swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this))); } if (destToken == dai) { uint256 chaiAmount = _swapOnUniswap(fromToken, IERC20(chai), amount); chai.exit(address(this), chaiAmount); return destToken.universalBalanceOf(address(this)); } return 0; } function _swapOnUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (!fromToken.isETH()) { IAaveToken fromAave = _getAaveToken(fromToken); fromToken.universalApprove(aave.core(), amount); aave.deposit(fromToken, amount, 1101); return _swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this))); } if (!destToken.isETH()) { IAaveToken toAave = _getAaveToken(destToken); uint256 aaveAmount = _swapOnUniswap(fromToken, IERC20(toAave), amount); toAave.redeem(aaveAmount); return aaveAmount; } return 0; } function _swapOnMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { IMooniswap mooniswap = mooniswapRegistry.target(); fromToken.universalApprove(address(mooniswap), amount); return mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0 ); } function _swapOnKyber( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { fromToken.universalApprove(address(kyberNetworkProxy), amount); return kyberNetworkProxy.tradeWithHint.value(fromToken.isETH() ? amount : 0)( fromToken.isETH() ? ETH_ADDRESS : fromToken, amount, destToken.isETH() ? ETH_ADDRESS : destToken, address(this), 1 << 255, 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, "" ); } function _swapOnBancor( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorNetworkPathFinder.generatePath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); fromToken.universalApprove(address(bancorNetwork), amount); return bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1); } function _swapOnOasis( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 approveToken = fromToken.isETH() ? weth : fromToken; approveToken.universalApprove(address(oasisExchange), amount); uint256 returnAmount = oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 1 ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } return returnAmount; } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal); returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount); fromTokenReal.universalTransfer(address(exchange), amount); if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) { exchange.swap(0, returnAmount, address(this), ""); } else { exchange.swap(returnAmount, 0, address(this), ""); } if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( midToken, destToken, _swapOnUniswapV2Internal( fromToken, midToken, amount ) ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2Internal( fromToken, destToken, amount ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, weth, destToken, amount ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, dai, destToken, amount ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { return _swapOnUniswapV2OverMid( fromToken, usdc, destToken, amount ); } function _swapOnBalancerX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 poolIndex ) internal returns(uint256) { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (fromToken.isETH()) { weth.deposit.value(amount)(); } (fromToken.isETH() ? weth : 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 ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 0); } function _swapOnBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 1); } function _swapOnBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal returns(uint256) { _swapOnBalancerX(fromToken, destToken, amount, 2); } } // File: contracts/OneSplitMultiPath.sol pragma solidity ^0.5.0; contract OneSplitMultiPathBase is IOneSplitConsts, OneSplitRoot { function _getMultiPathToken(uint256 flags) internal pure returns(IERC20 midToken) { uint256[8] memory allFlags = [ FLAG_ENABLE_MULTI_PATH_ETH, FLAG_ENABLE_MULTI_PATH_DAI, FLAG_ENABLE_MULTI_PATH_USDC, FLAG_ENABLE_MULTI_PATH_USDT, FLAG_ENABLE_MULTI_PATH_WBTC, FLAG_ENABLE_MULTI_PATH_TBTC, FLAG_ENABLE_MULTI_PATH_RENBTC, FLAG_ENABLE_MULTI_PATH_COMP ]; IERC20[8] memory allMidTokens = [ ETH_ADDRESS, dai, usdc, usdt, wbtc, tbtc, renbtc, comp ]; for (uint i = 0; i < allFlags.length; i++) { if (flags.check(allFlags[i])) { require(midToken == IERC20(0), "OneSplit: Do not use multipath with each other"); midToken = allMidTokens[i]; } } } } contract OneSplitMultiPathView is OneSplitViewWrapBase, OneSplitMultiPathBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns ( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } IERC20 midToken = _getMultiPathToken(flags); if (midToken != IERC20(0)) { if (_tokensEqual(fromToken, midToken) || _tokensEqual(midToken, destToken)) { return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } // Stack too deep uint256 _flags = flags; IERC20 _destToken = destToken; uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, midToken, amount, parts, _flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, midToken, _destTokenEthPriceTimesGasPrice ) ); uint256[] memory dist; uint256 estimateGasAmount2; (returnAmount, estimateGasAmount2, dist) = super.getExpectedReturnWithGas( midToken, destToken, returnAmount, parts, _flags, // Double tap into the same source is not an issue since price wouldn't be worse destTokenEthPriceTimesGasPrice ); for (uint i = 0; i < distribution.length; i++) { distribution[i] = distribution[i].add(dist[i] << 8); } return (returnAmount, estimateGasAmount + estimateGasAmount2, distribution); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMultiPath is OneSplitBaseWrap, OneSplitMultiPathBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { IERC20 midToken = _getMultiPathToken(flags); if (midToken != IERC20(0) && !_tokensEqual(fromToken, midToken) && !_tokensEqual(midToken, destToken)) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & 0xFF; } super._swap( fromToken, midToken, amount, dist, flags ); for (uint i = 0; i < distribution.length; i++) { dist[i] = (distribution[i] >> 8) & 0xFF; } super._swap( midToken, destToken, midToken.universalBalanceOf(address(this)), dist, flags ); return; } super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitCompound.sol pragma solidity ^0.5.0; contract OneSplitCompoundBase { function _getCompoundUnderlyingToken(IERC20 token) internal pure returns(IERC20) { if (token == IERC20(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5)) { // ETH return IERC20(0); } if (token == IERC20(0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643)) { // DAI return IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); } if (token == IERC20(0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E)) { // BAT return IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF); } if (token == IERC20(0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1)) { // REP return IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862); } if (token == IERC20(0x39AA39c021dfbaE8faC545936693aC917d5E7563)) { // USDC return IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); } if (token == IERC20(0xC11b1268C1A384e55C48c2391d8d480264A3A7F4)) { // WBTC return IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); } if (token == IERC20(0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407)) { // ZRX return IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498); } if (token == IERC20(0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9)) { // USDT return IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); } return IERC20(-1); } } contract OneSplitCompoundView is OneSplitViewWrapBase, OneSplitCompoundBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = _getCompoundUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn( underlying, destToken, amount.mul(compoundRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getCompoundUnderlyingToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18) ); return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitCompound is OneSplitBaseWrap, OneSplitCompoundBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compoundSwap( fromToken, destToken, amount, distribution, flags ); } function _compoundSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = _getCompoundUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { ICompoundToken(address(fromToken)).redeem(amount); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return _compoundSwap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _getCompoundUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { cETH.mint.value(underlyingAmount)(); } else { underlying.universalApprove(address(destToken), underlyingAmount); ICompoundToken(address(destToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IFulcrum.sol pragma solidity ^0.5.0; contract IFulcrumToken is IERC20 { function tokenPrice() external view returns (uint256); function loanTokenAddress() external view returns (address); function mintWithEther(address receiver) external payable returns (uint256 mintAmount); function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount); function burnToEther(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); } // File: contracts/OneSplitFulcrum.sol pragma solidity ^0.5.0; contract OneSplitFulcrumBase { using UniversalERC20 for IERC20; function _isFulcrumToken(IERC20 token) internal view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature( "name()" )); if (!success) { return IERC20(-1); } bool foundBZX = false; for (uint i = 0; i + 6 < data.length; i++) { if (data[i + 0] == "F" && data[i + 1] == "u" && data[i + 2] == "l" && data[i + 3] == "c" && data[i + 4] == "r" && data[i + 5] == "u" && data[i + 6] == "m") { foundBZX = true; break; } } if (!foundBZX) { return IERC20(-1); } (success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( IFulcrumToken(address(token)).loanTokenAddress.selector )); if (!success) { return IERC20(-1); } return abi.decode(data, (IERC20)); } } contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn( underlying, destToken, amount.mul(fulcrumRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 381_000, distribution); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18) ); return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, destToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { if (underlying.isETH()) { IFulcrumToken(address(fromToken)).burnToEther(address(this), amount); } else { IFulcrumToken(address(fromToken)).burn(address(this), amount); } uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return super._swap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { underlying.universalApprove(address(destToken), underlyingAmount); IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, chai.chaiToDai(amount), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 197_000, distribution); } if (destToken == IERC20(chai)) { uint256 price = chai.chaiPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(1e18).div(price) ); return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } if (destToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(chai), daiBalance); chai.join(address(this), daiBalance); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IBdai.sol pragma solidity ^0.5.0; contract IBdai is IERC20 { function join(uint256) external; function exit(uint256) external; } // File: contracts/OneSplitBdai.sol pragma solidity ^0.5.0; contract OneSplitBdaiBase { IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 227_000, distribution); } if (destToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { bdai.exit(amount); uint256 btuBalance = btu.balanceOf(address(this)); if (btuBalance > 0) { (,uint256[] memory btuDistribution) = getExpectedReturn( btu, destToken, btuBalance, 1, flags ); _swap( btu, destToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, destToken, amount, distribution, flags ); } if (destToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(bdai), daiBalance); bdai.join(daiBalance); return; } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIearn.sol pragma solidity ^0.5.0; contract IIearn is IERC20 { function token() external view returns(IERC20); function calcPoolValueInToken() external view returns(uint256); function deposit(uint256 _amount) external; function withdraw(uint256 _shares) external; } // File: contracts/OneSplitIearn.sol pragma solidity ^0.5.0; contract OneSplitIearnBase { function _yTokens() internal pure returns(IIearn[13] memory) { return [ IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01), IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9), IIearn(0x73a052500105205d34Daf004eAb301916DA8190f), IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D), IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e), IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600), IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE), IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32), IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447), IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951), IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc), IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E), IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59) ]; } } contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _iearnGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { (returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn( yTokens[i].token(), destToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 260_000, distribution); } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; IERC20 token = yTokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()) ); return( returnAmount .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), estimateGasAmount + 743_000, distribution ); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, destToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(yTokens[i]), underlyingBalance); yTokens[i].deposit(underlyingBalance); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIdle.sol pragma solidity ^0.5.0; contract IIdle is IERC20 { function token() external view returns (IERC20); function tokenPrice() external view returns (uint256); function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts) external returns (uint256 mintedTokens); function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts) external returns (uint256 redeemedTokens); } // File: contracts/OneSplitIdle.sol pragma solidity ^0.5.0; contract OneSplitIdleBase { function _idleTokens() internal pure returns(IIdle[8] memory) { // https://developers.idle.finance/contracts-and-codebase return [ // V3 IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934), IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6), IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D), IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB), IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C), IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B), // V2 IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _idleGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { (returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn( tokens[i].token(), destToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 2_400_000, distribution); } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 _price = tokens[i].tokenPrice(); IERC20 token = tokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(_price).div(1e18) ); return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, destToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0)); _idleSwap(underlying, destToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(tokens[i]), underlyingBalance); tokens[i].mintIdleToken(underlyingBalance, new uint256[](0)); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/OneSplitAave.sol pragma solidity ^0.5.0; contract OneSplitAaveBase { function _getAaveUnderlyingToken(IERC20 token) internal pure returns(IERC20) { if (token == IERC20(0x3a3A65aAb0dd2A17E3F1947bA16138cd37d08c04)) { // ETH return IERC20(0); } if (token == IERC20(0xfC1E690f61EFd961294b3e1Ce3313fBD8aa4f85d)) { // DAI return IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); } if (token == IERC20(0x9bA00D6856a4eDF4665BcA2C2309936572473B7E)) { // USDC return IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); } if (token == IERC20(0x625aE63000f46200499120B906716420bd059240)) { // SUSD return IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); } if (token == IERC20(0x6Ee0f7BB50a54AB5253dA0667B0Dc2ee526C30a8)) { // BUSD return IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); } if (token == IERC20(0x4DA9b813057D04BAef4e5800E36083717b4a0341)) { // TUSD return IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); } if (token == IERC20(0x71fc860F7D3A592A4a98740e39dB31d25db65ae8)) { // USDT return IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); } if (token == IERC20(0xE1BA0FB44CCb0D11b80F92f4f8Ed94CA3fF51D00)) { // BAT return IERC20(0x0D8775F648430679A709E98d2b0Cb6250d2887EF); } if (token == IERC20(0x9D91BE44C06d373a8a226E1f3b146956083803eB)) { // KNC return IERC20(0xdd974D5C2e2928deA5F71b9825b8b646686BD200); } if (token == IERC20(0x7D2D3688Df45Ce7C552E19c27e007673da9204B8)) { // LEND return IERC20(0x80fB784B7eD66730e8b1DBd9820aFD29931aab03); } if (token == IERC20(0xA64BD6C70Cb9051F6A9ba1F163Fdc07E0DfB5F84)) { // LINK return IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA); } if (token == IERC20(0x6FCE4A401B6B80ACe52baAefE4421Bd188e76F6f)) { // MANA return IERC20(0x0F5D2fB29fb7d3CFeE444a200298f468908cC942); } if (token == IERC20(0x7deB5e830be29F91E298ba5FF1356BB7f8146998)) { // MKR return IERC20(0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2); } if (token == IERC20(0x71010A9D003445aC60C4e6A7017c1E89A477B438)) { // REP return IERC20(0x1985365e9f78359a9B6AD760e32412f4a445E862); } if (token == IERC20(0x328C4c80BC7aCa0834Db37e6600A6c49E12Da4DE)) { // SNX return IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F); } if (token == IERC20(0xFC4B8ED459e00e5400be803A9BB3954234FD50e3)) { // WBTC return IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); } if (token == IERC20(0x6Fb0855c404E09c47C3fBCA25f08d4E41f9F062f)) { // ZRX return IERC20(0xE41d2489571d322189246DaFA5ebDe1F4699F498); } return IERC20(-1); } } contract OneSplitAaveView is OneSplitViewWrapBase, OneSplitAaveBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { (returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn( underlying, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 670_000, distribution); } underlying = _getAaveUnderlyingToken(destToken); if (underlying != IERC20(-1)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 310_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitAave is OneSplitBaseWrap, OneSplitAaveBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, destToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = _getAaveUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, destToken, amount, distribution, flags ); } underlying = _getAaveUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); underlying.universalApprove(aave.core(), underlyingAmount); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice); } if (destToken == weth || destToken == bancorEtherToken) { return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, destToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (destToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (destToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitMStable.sol pragma solidity ^0.5.0; contract OneSplitMStableView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, destToken); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, dai); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, returnAmount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 300_000, distribution); } } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { (,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { IERC20 _destToken = destToken; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, dai, destTokenEthPriceTimesGasPrice ) ); (,, returnAmount) = musd_helper.getRedeemValidity(dai, returnAmount, destToken); return (returnAmount, estimateGasAmount + 300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMStable is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken); musd.redeem( destToken, result ); } else { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai); musd.redeem( dai, result ); super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } return; } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } else { super._swap( fromToken, dai, amount, distribution, flags ); musd.swap( dai, destToken, dai.balanceOf(address(this)), address(this) ); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IDMM.sol pragma solidity ^0.5.0; interface IDMMController { function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20); } contract IDMM is IERC20 { function getCurrentExchangeRate() public view returns(uint256); function mint(uint256 underlyingAmount) public returns(uint256); function redeem(uint256 amount) public returns(uint256); } // File: contracts/OneSplitDMM.sol pragma solidity ^0.5.0; contract OneSplitDMMBase { IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2); function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) { (bool success, bytes memory data) = address(_dmmController).staticcall( abi.encodeWithSelector( _dmmController.getUnderlyingTokenForDmm.selector, token ) ); if (!success || data.length == 0) { return IERC20(-1); } return abi.decode(data, (IERC20)); } function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) { (bool success, bytes memory data) = address(dmm).staticcall( abi.encodeWithSelector( dmm.getCurrentExchangeRate.selector ) ); if (!success || data.length == 0) { return 0; } return abi.decode(data, (uint256)); } } contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _dmmGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _dmmGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } IERC20 _fromToken = fromToken; (returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn( underlying, destToken, amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } uint256 price = _getDMMExchangeRate(IDMM(address(destToken))); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(price).div(1e18) ); return ( returnAmount.mul(1e18).div(price), estimateGasAmount + 430_000, distribution ); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _dmmSwap( fromToken, destToken, amount, distribution, flags ); } function _dmmSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IDMM(address(fromToken)).redeem(amount); uint256 balance = underlying.universalBalanceOf(address(this)); if (underlying == weth) { weth.withdraw(balance); } _dmmSwap( (underlying == weth) ? ETH_ADDRESS : underlying, destToken, balance, distribution, flags ); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, (underlying == weth) ? ETH_ADDRESS : underlying, amount, distribution, flags ); uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this)); if (underlying == weth) { weth.deposit.value(underlyingAmount); } underlying.universalApprove(address(destToken), underlyingAmount); IDMM(address(destToken)).mint(underlyingAmount); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; //import "./OneSplitSmartToken.sol"; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMStableView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, OneSplitDMMView, OneSplitMultiPathView //OneSplitSmartTokenView { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplit) public { oneSplitView = _oneSplit; } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWrap is OneSplitBaseWrap, OneSplitMStable, OneSplitChai, OneSplitBdai, OneSplitAave, OneSplitFulcrum, OneSplitCompound, OneSplitIearn, OneSplitIdle, OneSplitWeth, OneSplitDMM, OneSplitMultiPath //OneSplitSmartToken { IOneSplitView public oneSplitView; IOneSplit public oneSplit; constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public { oneSplitView = _oneSplitView; oneSplit = _oneSplit; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256 parts, uint256 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, flags, 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 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 ); 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":"_oneSplitView","type":"address"},{"internalType":"contract IOneSplit","name":"_oneSplit","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[{"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":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256[]","name":"destTokenEthPriceTimesGasPrices","type":"uint256[]"}],"name":"getExpectedReturnWithGasMulti","outputs":[{"internalType":"uint256[]","name":"returnAmounts","type":"uint256[]"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplit","outputs":[{"internalType":"contract IOneSplit","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplitView","outputs":[{"internalType":"contract IOneSplitView","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"swapMulti","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405162004e2938038062004e298339818101604052604081101561003557600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b03199182161790915560018054939092169216919091179055614dac806200007d6000396000f3fe6080604052600436106100705760003560e01c80634c8ea8711161004e5780634c8ea8711461029d5780638373f2651461047f578063e2a7515e14610536578063fbe4ed95146105fe57610070565b8063085e2c5b1461007f578063370c83c41461012957806343ee21f01461026c575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060800135610613565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b61025a600480360360a081101561013f57600080fd5b810190602081018135600160201b81111561015957600080fd5b82018360208201111561016b57600080fd5b803590602001918460208302840111600160201b8311171561018c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156101e757600080fd5b8201836020820111156101f957600080fd5b803590602001918460208302840111600160201b8311171561021a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610636915050565b60408051918252519081900360200190f35b34801561027857600080fd5b50610281610866565b604080516001600160a01b039092168252519081900360200190f35b3480156102a957600080fd5b506103df600480360360a08110156102c057600080fd5b810190602081018135600160201b8111156102da57600080fd5b8201836020820111156102ec57600080fd5b803590602001918460208302840111600160201b8311171561030d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595604081013595509193509150608081019060600135600160201b81111561036e57600080fd5b82018360208201111561038057600080fd5b803590602001918460208302840111600160201b831117156103a157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610875945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b83811015610429578181015183820152602001610411565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610468578181015183820152602001610450565b505050509050019550505050505060405180910390f35b34801561048b57600080fd5b506104d4600480360360c08110156104a257600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a66565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610520578181015183820152602001610508565b5050505090500194505050505060405180910390f35b61025a600480360360c081101561054c57600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561058b57600080fd5b82018360208201111561059d57600080fd5b803590602001918460208302840111600160201b831117156105be57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610bbd915050565b34801561060a57600080fd5b50610281610cb9565b6000606061062687878787876000610a66565b9199919850909650505050505050565b600061066c3330878960008151811061064b57fe5b60200260200101516001600160a01b0316610cc8909392919063ffffffff16565b61069c308760008151811061067d57fe5b60200260200101516001600160a01b0316610de790919063ffffffff16565b905060015b8651811015610807578681815181106106b657fe5b60200260200101516001600160a01b03168760018303815181106106d657fe5b60200260200101516001600160a01b031614156106f2576107ff565b6060845160405190808252806020026020018201604052801561071f578160200160208202803883390190505b50905060005b855181101561076d576001830360080286828151811061074157fe5b6020026020010151901c60ff1682828151811061075a57fe5b6020908102919091010152600101610725565b506107a488600184038151811061078057fe5b602002602001015189848151811061079457fe5b6020026020010151858488610e93565b6107b43089848151811061067d57fe5b92506107fc336107cd308b600187038151811061067d57fe5b8a60018603815181106107dc57fe5b60200260200101516001600160a01b0316610fe09092919063ffffffff16565b50505b6001016106a1565b50838110156108475760405162461bcd60e51b8152600401808060200182810382526035815260200180614c6a6035913960400191505060405180910390fd5b61085c33828860018a5103815181106107dc57fe5b5095945050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156108aa578160200160208202803883390190505b50935060015b8951811015610a59578981815181106108c557fe5b60200260200101516001600160a01b03168a60018303815181106108e557fe5b60200260200101516001600160a01b0316141561090157610a51565b60608a905061097581600184038151811061091857fe5b602002602001015182848151811061092c57fe5b6020026020010151846001146109585788600286038151811061094b57fe5b602002602001015161095a565b8c5b8c8c8c888151811061096857fe5b6020026020010151610a66565b88600186038151811061098457fe5b60209081029190910101929092529a5092506109a6858b63ffffffff61105e16565b94508351600014156109e15782516040519080825280602002602001820160405280156109dd578160200160208202803883390190505b5093505b60005b8451811015610a4e57610a2f60018403600802858381518110610a0357fe5b6020026020010151901b868381518110610a1957fe5b602002602001015161105e90919063ffffffff16565b858281518110610a3b57fe5b60209081029190910101526001016109e4565b50505b6001016108b0565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610ad957600080fd5b505afa158015610aed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610b1657600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610b4057600080fd5b908301906020820185811115610b5557600080fd5b82518660208202830111600160201b82111715610b7157600080fd5b82525081516020918201928201910280838360005b83811015610b9e578181015183820152602001610b86565b5050505090500160405250505092509250925096509650969350505050565b6000610bda6001600160a01b03881633308863ffffffff610cc816565b6000610bf56001600160a01b0389163063ffffffff610de716565b9050610c048888838787610e93565b610c1d6001600160a01b0388163063ffffffff610de716565b915084821015610c5e5760405162461bcd60e51b8152600401808060200182810382526035815260200180614c6a6035913960400191505060405180910390fd5b610c786001600160a01b038816338463ffffffff610fe016565b50610cad33610c966001600160a01b038b163063ffffffff610de716565b6001600160a01b038b16919063ffffffff610fe016565b50509695505050505050565b6000546001600160a01b031681565b80610cd257610de1565b610cdb846110b8565b15610dc6576001600160a01b03831633148015610cf85750803410155b610d335760405162461bcd60e51b815260040180806020018281038252602b815260200180614cbf602b913960400191505060405180910390fd5b6001600160a01b0382163014610d7b576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610d79573d6000803e3d6000fd5b505b80341115610dc157336108fc610d97348463ffffffff6110f416565b6040518115909202916000818181858888f19350505050158015610dbf573d6000803e3d6000fd5b505b610de1565b610de16001600160a01b03851684848463ffffffff61113616565b50505050565b6000610df2836110b8565b15610e0857506001600160a01b03811631610e8d565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610e5e57600080fd5b505afa158015610e72573d6000803e3d6000fd5b505050506040513d6020811015610e8857600080fd5b505190505b92915050565b6000610e9e82611190565b90506001600160a01b03811615801590610ebf5750610ebd8682611373565b155b8015610ed25750610ed08186611373565b155b15610fca5760608351604051908082528060200260200182016040528015610f04578160200160208202803883390190505b50905060005b8451811015610f4957848181518110610f1f57fe5b602002602001015160ff16828281518110610f3657fe5b6020908102919091010152600101610f0a565b50610f5787838784876113b8565b60005b8451811015610f9d576008858281518110610f7157fe5b6020026020010151901c60ff16828281518110610f8a57fe5b6020908102919091010152600101610f5a565b50610fc38287610fbc6001600160a01b0383163063ffffffff610de716565b84876113b8565b5050610fd9565b610fd786868686866113b8565b505b5050505050565b600081610fef57506001611057565b610ff8846110b8565b15611039576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611033573d6000803e3d6000fd5b50611057565b6110536001600160a01b038516848463ffffffff6113c516565b5060015b9392505050565b600082820183811015611057576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60006001600160a01b03821615806110ec57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b600061105783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061141c565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610de19085906114b3565b600061119a614c2b565b604051806101000160405280610200815260200162010000815260200162020000815260200164040000000081526020016408000000008152602001641000000000815260200164200000000081526020016701000000000000008152509050611202614c2b565b50604080516101008101825273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8152600080516020614c9f833981519152602082015273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489181019190915273dac17f958d2ee523a2206206994597c13d831ec76060820152732260fac5e5542a773aa44fbcfedf7c193bc2c5996080820152731bbe271d15bb64df0bc6cd28df9ff322f2ebd84760a082015273eb4c2781e4eba804ce9a9803c67d0893436bb27d60c082015273c00e94cb662c3520282e6f5717214004a7f2688860e082015260005b600881101561136b576113048382600881106112f257fe5b6020020151869063ffffffff61166b16565b15611363576001600160a01b0384161561134f5760405162461bcd60e51b815260040180806020018281038252602e815260200180614cea602e913960400191505060405180910390fd5b81816008811061135b57fe5b602002015193505b6001016112da565b505050919050565b6000611387836001600160a01b03166110b8565b80156113a057506113a0826001600160a01b03166110b8565b806110575750506001600160a01b0391821691161490565b610fd98585858585611671565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526114179084906114b3565b505050565b600081848411156114ab5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611470578181015183820152602001611458565b50505050905090810190601f16801561149d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6114c5826001600160a01b03166119bf565b611516576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106115545780518252601f199092019160209182019101611535565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146115b6576040519150601f19603f3d011682016040523d82523d6000602084013e6115bb565b606091505b509150915081611612576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115610de15780806020019051602081101561162e57600080fd5b5051610de15760405162461bcd60e51b815260040180806020018281038252602a815260200180614d18602a913960400191505060405180910390fd5b16151590565b836001600160a01b0316856001600160a01b0316141561169057610fd9565b6116a6816508000000000063ffffffff61166b16565b15156116bc82634000000063ffffffff61166b16565b151514156119b25760006116cf866119fb565b90506001600160a01b038082161461185757856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050506040513d602081101561175157600080fd5b506000905061176f6001600160a01b0383163063ffffffff610de716565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156118095773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156117f057600080fd5b505af1158015611804573d6000803e3d6000fd5b505050505b6118556001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214611836578261184c565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b87838787611671565b505b611860856119fb565b90506001600160a01b03808216146119b0576118be866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146118a057826118b6565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686611b2f565b6000611919306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146118ee5783611904565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff610de716565b90505b6119366001600160a01b038316878363ffffffff611b3c16565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b505050506040513d60208110156119a657600080fd5b50610fd992505050565b505b610fd98585858585611b2f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906119f357508115155b949350505050565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b60208310611a895780518252601f199092019160209182019101611a6a565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611ae9576040519150601f19603f3d011682016040523d82523d6000602084013e611aee565b606091505b5091509150811580611aff57508051155b15611b1057600019925050506110ef565b808060200190516020811015611b2557600080fd5b5051949350505050565b610fd98585858585611c30565b611b45836110b8565b6114175780611b6e57611b696001600160a01b03841683600063ffffffff611f7916565b611417565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611bbf57600080fd5b505afa158015611bd3573d6000803e3d6000fd5b505050506040513d6020811015611be957600080fd5b5051905081811015610de1578015611c1657611c166001600160a01b03851684600063ffffffff611f7916565b610de16001600160a01b038516848463ffffffff611f7916565b836001600160a01b0316856001600160a01b03161415611c4f57610fd9565b611c62816208000063ffffffff61166b16565b1515611c7882634000000063ffffffff61166b16565b15151415611f6c576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611da657604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015611d6857600080fd5b505af1158015611d7c573d6000803e3d6000fd5b50505050611da173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8585858561208c565b610fd9565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611e2457604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611cfe57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611ed757611e6a8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611c30565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611eb957600080fd5b505af1158015611ecd573d6000803e3d6000fd5b5050505050610fd9565b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611f6c57611f1d8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611c30565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611eb957600080fd5b610fd9858585858561208c565b801580611fff575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611fd157600080fd5b505afa158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5051155b61203a5760405162461bcd60e51b8152600401808060200182810382526036815260200180614d426036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526114179084906114b3565b610fd985858585855b6120a8816280000063ffffffff61166b16565b156120bd82634000000063ffffffff61166b16565b15141561250f576120cc614c2b565b6120d461251c565b905060005b60088110156122a7578181600881106120ee57fe5b60200201516001600160a01b0316876001600160a01b0316141561229f57600082826008811061211a57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561215757600080fd5b505afa15801561216b573d6000803e3d6000fd5b505050506040513d602081101561218157600080fd5b50519050600083836008811061219357fe5b60200201516001600160a01b031663c85c93aa88600160006040519080825280602002602001820160405280156121d4578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561223457818101518382015260200161221c565b50505050905001945050505050602060405180830381600087803b15801561225b57600080fd5b505af115801561226f573d6000803e3d6000fd5b505050506040513d602081101561228557600080fd5b505190506122968289838989612095565b50505050610fd9565b6001016120d9565b5060005b600881101561250c578181600881106122c057fe5b60200201516001600160a01b0316866001600160a01b031614156125045760008282600881106122ec57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561232957600080fd5b505afa15801561233d573d6000803e3d6000fd5b505050506040513d602081101561235357600080fd5b505190506123648882888888612602565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156123ae57600080fd5b505afa1580156123c2573d6000803e3d6000fd5b505050506040513d60208110156123d857600080fd5b505190506124078484600881106123eb57fe5b60200201516001600160a01b038416908363ffffffff611b3c16565b83836008811061241357fe5b60200201516001600160a01b0316633cfcef64826000604051908082528060200260200182016040528015612452578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156124a8578181015183820152602001612490565b505050509050019350505050602060405180830381600087803b1580156124ce57600080fd5b505af11580156124e2573d6000803e3d6000fd5b505050506040513d60208110156124f857600080fd5b50610fd9945050505050565b6001016122ab565b50505b610fd98585858585612602565b612524614c2b565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b610fd985858585855b836001600160a01b0316856001600160a01b0316141561262a57610fd9565b61263c8161080063ffffffff61166b16565b151561265282634000000063ffffffff61166b16565b151514156129ed57612662614c4a565b61266a6129fa565b905060005b600d811015612827578181600d811061268457fe5b60200201516001600160a01b0316876001600160a01b0316141561281f5760008282600d81106126b057fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126ed57600080fd5b505afa158015612701573d6000803e3d6000fd5b505050506040513d602081101561271757600080fd5b505190508282600d811061272757fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506128178188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156127e457600080fd5b505afa1580156127f8573d6000803e3d6000fd5b505050506040513d602081101561280e57600080fd5b5051888861260b565b505050610fd9565b60010161266f565b5060005b600d8110156129ea578181600d811061284057fe5b60200201516001600160a01b0316866001600160a01b031614156129e25760008282600d811061286c57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128a957600080fd5b505afa1580156128bd573d6000803e3d6000fd5b505050506040513d60208110156128d357600080fd5b505190506128e48882888888612b67565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561292e57600080fd5b505afa158015612942573d6000803e3d6000fd5b505050506040513d602081101561295857600080fd5b5051905061296b8484600d81106123eb57fe5b8383600d811061297757fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156129c157600080fd5b505af11580156129d5573d6000803e3d6000fd5b5050505050505050610fd9565b60010161282b565b50505b610fd98585858585612b67565b612a02614c4a565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b610fd985858585855b836001600160a01b0316856001600160a01b03161415612b8f57610fd9565b612ba081601063ffffffff61166b16565b1515612bb682634000000063ffffffff61166b16565b15151415612d43576000612bc986612d50565b90506001600160a01b0380821614612c7857856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612c2157600080fd5b505af1158015612c35573d6000803e3d6000fd5b505050506040513d6020811015612c4b57600080fd5b5060009050612c696001600160a01b0383163063ffffffff610de716565b9050610fc38287838787612b70565b612c8185612d50565b90506001600160a01b0380821614612d4157612ca08682868686612f42565b6000612cbb6001600160a01b0383163063ffffffff610de716565b9050612ccf826001600160a01b03166110b8565b1561191c57734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612d2357600080fd5b505af1158015612d37573d6000803e3d6000fd5b5050505050610fc3565b505b610fd98585858585612f42565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed51415612d7f575060006110ef565b6001600160a01b038216735d3a536e4d6dbd6114cc1ead35777bab948e36431415612db95750600080516020614c9f8339815191526110ef565b6001600160a01b038216736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e1415612df95750730d8775f648430679a709e98d2b0cb6250d2887ef6110ef565b6001600160a01b03821673158079ee67fce2f58472a96584a73c7ab9ac95c11415612e395750731985365e9f78359a9b6ad760e32412f4a445e8626110ef565b6001600160a01b0382167339aa39c021dfbae8fac545936693ac917d5e75631415612e79575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486110ef565b6001600160a01b03821673c11b1268c1a384e55c48c2391d8d480264a3a7f41415612eb95750732260fac5e5542a773aa44fbcfedf7c193bc2c5996110ef565b6001600160a01b03821673b3319f5d18bc0d84dd1b4825dcde5d5f7266d4071415612ef9575073e41d2489571d322189246dafa5ebde1f4699f4986110ef565b6001600160a01b03821673f650c3d88d12db855b8bf7d11be6c55a4e07dcc91415612f39575073dac17f958d2ee523a2206206994597c13d831ec76110ef565b50600019919050565b610fd98585858585836001600160a01b0316856001600160a01b03161415612f6957610fd9565b612f7a81602063ffffffff61166b16565b1515612f9082634000000063ffffffff61166b16565b15151415613237576000612fa386613244565b90506001600160a01b03808216146130f357612fc7816001600160a01b03166110b8565b1561304d576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b15801561301b57600080fd5b505af115801561302f573d6000803e3d6000fd5b505050506040513d602081101561304557600080fd5b506130c99050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b15801561309c57600080fd5b505af11580156130b0573d6000803e3d6000fd5b505050506040513d60208110156130c657600080fd5b50505b60006130e46001600160a01b0383163063ffffffff610de716565b9050610fc382878387876135ba565b6130fc85613244565b90506001600160a01b03808216146132355761311b86828686866135ba565b60006131366001600160a01b0383163063ffffffff610de716565b905061314a826001600160a01b03166110b8565b156131cc5760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b15801561319957600080fd5b505af11580156131ad573d6000803e3d6000fd5b50505050506040513d60208110156131c457600080fd5b50610fc39050565b6131e66001600160a01b038316878363ffffffff611b3c16565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b15801561197c57600080fd5b505b610fd985858585856135ba565b6000613258826001600160a01b03166110b8565b1561326657506000196110ef565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b602083106132d15780518252601f1990920191602091820191016132b2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613332576040519150601f19603f3d011682016040523d82523d6000602084013e613337565b606091505b50915091508161334d57600019925050506110ef565b6000805b82518160060110156134a65782816000018151811061336c57fe5b6020910101516001600160f81b031916602360f91b1480156133af575082816001018151811061339857fe5b6020910101516001600160f81b031916607560f81b145b80156133dc57508281600201815181106133c557fe5b6020910101516001600160f81b031916601b60fa1b145b801561340957508281600301815181106133f257fe5b6020910101516001600160f81b031916606360f81b145b8015613436575082816004018151811061341f57fe5b6020910101516001600160f81b031916603960f91b145b8015613463575082816005018151811061344c57fe5b6020910101516001600160f81b031916607560f81b145b8015613490575082816006018151811061347957fe5b6020910101516001600160f81b031916606d60f81b145b1561349e57600191506134a6565b600101613351565b50806134b95760001993505050506110ef565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b6020831061351c5780518252601f1990920191602091820191016134fd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d806000811461357d576040519150601f19603f3d011682016040523d82523d6000602084013e613582565b606091505b5090935091508261359a5760001993505050506110ef565b8180602001905160208110156135af57600080fd5b505195945050505050565b610fd985858585855b836001600160a01b0316856001600160a01b031614156135e257610fd9565b6135f381608063ffffffff61166b16565b151561360982634000000063ffffffff61166b16565b1515141561385957600061361c86613866565b90506001600160a01b038082161461369f57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561367457600080fd5b505af1158015613688573d6000803e3d6000fd5b5050505061369981868686866135c3565b50610fd9565b6136a885613866565b90506001600160a01b0380821614613857576136c78682868686613c8a565b60006136e26001600160a01b0383163063ffffffff610de716565b905061377773398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b15801561373457600080fd5b505afa158015613748573d6000803e3d6000fd5b505050506040513d602081101561375e57600080fd5b50516001600160a01b038416908363ffffffff611b3c16565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666137a36001600160a01b0385166110b8565b6137ae5760006137b0565b825b6137c2856001600160a01b03166110b8565b6137cc57846137e2565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b15801561383757600080fd5b505af115801561384b573d6000803e3d6000fd5b50505050505050610fd9565b505b610fd98585858585613c8a565b60006001600160a01b038216733a3a65aab0dd2a17e3f1947ba16138cd37d08c041415613895575060006110ef565b6001600160a01b03821673fc1e690f61efd961294b3e1ce3313fbd8aa4f85d14156138cf5750600080516020614c9f8339815191526110ef565b6001600160a01b038216739ba00d6856a4edf4665bca2c2309936572473b7e141561390f575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486110ef565b6001600160a01b03821673625ae63000f46200499120b906716420bd059240141561394f57507357ab1ec28d129707052df4df418d58a2d46d5f516110ef565b6001600160a01b038216736ee0f7bb50a54ab5253da0667b0dc2ee526c30a8141561398f5750734fabb145d64652a948d72533023f6e7a623c7c536110ef565b6001600160a01b038216734da9b813057d04baef4e5800e36083717b4a034114156139ca57506e085d4780b73119b644ae5ecd22b3766110ef565b6001600160a01b0382167371fc860f7d3a592a4a98740e39db31d25db65ae81415613a0a575073dac17f958d2ee523a2206206994597c13d831ec76110ef565b6001600160a01b03821673e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d001415613a4a5750730d8775f648430679a709e98d2b0cb6250d2887ef6110ef565b6001600160a01b038216739d91be44c06d373a8a226e1f3b146956083803eb1415613a8a575073dd974d5c2e2928dea5f71b9825b8b646686bd2006110ef565b6001600160a01b038216737d2d3688df45ce7c552e19c27e007673da9204b81415613aca57507380fb784b7ed66730e8b1dbd9820afd29931aab036110ef565b6001600160a01b03821673a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f841415613b0a575073514910771af9ca656af840dff83e8264ecf986ca6110ef565b6001600160a01b038216736fce4a401b6b80ace52baaefe4421bd188e76f6f1415613b4a5750730f5d2fb29fb7d3cfee444a200298f468908cc9426110ef565b6001600160a01b038216737deb5e830be29f91e298ba5ff1356bb7f81469981415613b8a5750739f8f72aa9304c8b593d555f12ef6589cc3a579a26110ef565b6001600160a01b0382167371010a9d003445ac60c4e6a7017c1e89a477b4381415613bca5750731985365e9f78359a9b6ad760e32412f4a445e8626110ef565b6001600160a01b03821673328c4c80bc7aca0834db37e6600a6c49e12da4de1415613c0a575073c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6110ef565b6001600160a01b03821673fc4b8ed459e00e5400be803a9bb3954234fd50e31415613c4a5750732260fac5e5542a773aa44fbcfedf7c193bc2c5996110ef565b6001600160a01b038216736fb0855c404e09c47c3fbca25f08d4e41f9f062f1415612f39575073e41d2489571d322189246dafa5ebde1f4699f4986110ef565b836001600160a01b0316856001600160a01b03161415613ca957610fd9565b613cbb8161040063ffffffff61166b16565b1515613cd182634000000063ffffffff61166b16565b15151415613fa8576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613e5e57736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613d5857600080fd5b505af1158015613d6c573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b158015613dc557600080fd5b505afa158015613dd9573d6000803e3d6000fd5b505050506040513d6020811015613def57600080fd5b505190508015613e43576060613e1d73b683d83a532e2cb7dfa5275eed3698436371cc9f8784600187610613565b915050613e4173b683d83a532e2cb7dfa5275eed3698436371cc9f87848487610e93565b505b613699600080516020614c9f83398151915286868686613fb1565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613fa857613e9e85600080516020614c9f833981519152858585613fb1565b604080516370a0823160e01b81523060048201529051600091600080516020614c9f833981519152916370a0823191602480820192602092909190829003018186803b158015613eed57600080fd5b505afa158015613f01573d6000803e3d6000fd5b505050506040513d6020811015613f1757600080fd5b50519050613f4e600080516020614c9f833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff611b3c16565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611eb957600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b03161415613fd057610fd9565b613fe181604063ffffffff61166b16565b1515613ff782634000000063ffffffff61166b16565b15151415614265576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c215141561411c576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b15801561407d57600080fd5b505af1158015614091573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051611da19350600080516020614c9f8339815191529250879183916370a0823191602480820192602092909190829003018186803b1580156140e957600080fd5b505afa1580156140fd573d6000803e3d6000fd5b505050506040513d602081101561411357600080fd5b5051858561426e565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c21514156142655761415c85600080516020614c9f83398151915285858561426e565b604080516370a0823160e01b81523060048201529051600091600080516020614c9f833981519152916370a0823191602480820192602092909190829003018186803b1580156141ab57600080fd5b505afa1580156141bf573d6000803e3d6000fd5b505050506040513d60208110156141d557600080fd5b5051905061420c600080516020614c9f8339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff611b3c16565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611eb957600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b0316141561428d57610fd9565b6142a3816502000000000063ffffffff61166b16565b15156142b982634000000063ffffffff61166b16565b15151415614ab9576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a514156147fc576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48148061432757506001600160a01b038416600080516020614c9f833981519152145b8061434e57506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b8061437057506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b156145705760408051633b3fb85360e21b81526001600160a01b03878116600483015260248201869052861660448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b1580156143e157600080fd5b505afa1580156143f5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561441e57600080fd5b815160208301805160405192949293830192919084600160201b82111561444457600080fd5b90830190602082018581111561445957600080fd5b8251600160201b81118282018810171561447257600080fd5b82525081516020918201929091019080838360005b8381101561449f578181015183820152602001614487565b50505050905090810190601f1680156144cc5780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b83526001600160a01b038d16600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b15801561453d57600080fd5b505af1158015614551573d6000803e3d6000fd5b505050506040513d602081101561456757600080fd5b50611da1915050565b60408051633b3fb85360e21b81526001600160a01b038716600482015260248101859052600080516020614c9f83398151915260448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b1580156145e857600080fd5b505afa1580156145fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561462557600080fd5b815160208301805160405192949293830192919084600160201b82111561464b57600080fd5b90830190602082018581111561466057600080fd5b8251600160201b81118282018810171561467957600080fd5b82525081516020918201929091019080838360005b838110156146a657818101518382015260200161468e565b50505050905090810190601f1680156146d35780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b8352600080516020614c9f833981519152600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b15801561474957600080fd5b505af115801561475d573d6000803e3d6000fd5b505050506040513d602081101561477357600080fd5b5050604080516370a0823160e01b8152306004820152905161369991600080516020614c9f83398151915291889183916370a0823191602480820192602092909190829003018186803b1580156147c957600080fd5b505afa1580156147dd573d6000803e3d6000fd5b505050506040513d60208110156147f357600080fd5b50518686614ac2565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415614ab9576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48148061486257506001600160a01b038516600080516020614c9f833981519152145b8061488957506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b806148ab57506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b15614981576148de6001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff611b3c16565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b15801561494f57600080fd5b505af1158015614963573d6000803e3d6000fd5b505050506040513d602081101561497957600080fd5b50611da19050565b61499c85600080516020614c9f833981519152858585614ac2565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c91600080516020614c9f83398151915291889183916370a08231916024808301926020929190829003018186803b158015614a0757600080fd5b505afa158015614a1b573d6000803e3d6000fd5b505050506040513d6020811015614a3157600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b158015614a8f57600080fd5b505af1158015614aa3573d6000803e3d6000fd5b505050506040513d6020811015610fc357600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b03161415614ae157610fd9565b610fd98585858585600154614b09906001600160a01b0387811691168563ffffffff611b3c16565b6001546001600160a01b039081169063e2a7515e90614b299088166110b8565b614b34576000614b36565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015614bce578181015183820152602001614bb6565b505050509050019750505050505050506020604051808303818588803b158015614bf757600080fd5b505af1158015614c0b573d6000803e3d6000fd5b50505050506040513d6020811015614c2257600080fd5b50505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28294f6e6553706c69743a20446f206e6f7420757365206d756c74697061746820776974682065616368206f746865725361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a72315820293752088a2aec2583d287e39911b8b86603464ae8a1e18961dd33188fb9876664736f6c634300051100320000000000000000000000002fdac0084b40d7c259a284d72e8ee43930262266000000000000000000000000712e990ffb170bfe8c0de8b4f25918589a80babe
Deployed Bytecode
0x6080604052600436106100705760003560e01c80634c8ea8711161004e5780634c8ea8711461029d5780638373f2651461047f578063e2a7515e14610536578063fbe4ed95146105fe57610070565b8063085e2c5b1461007f578063370c83c41461012957806343ee21f01461026c575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060800135610613565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b61025a600480360360a081101561013f57600080fd5b810190602081018135600160201b81111561015957600080fd5b82018360208201111561016b57600080fd5b803590602001918460208302840111600160201b8311171561018c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156101e757600080fd5b8201836020820111156101f957600080fd5b803590602001918460208302840111600160201b8311171561021a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610636915050565b60408051918252519081900360200190f35b34801561027857600080fd5b50610281610866565b604080516001600160a01b039092168252519081900360200190f35b3480156102a957600080fd5b506103df600480360360a08110156102c057600080fd5b810190602081018135600160201b8111156102da57600080fd5b8201836020820111156102ec57600080fd5b803590602001918460208302840111600160201b8311171561030d57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595604081013595509193509150608081019060600135600160201b81111561036e57600080fd5b82018360208201111561038057600080fd5b803590602001918460208302840111600160201b831117156103a157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610875945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b83811015610429578181015183820152602001610411565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610468578181015183820152602001610450565b505050509050019550505050505060405180910390f35b34801561048b57600080fd5b506104d4600480360360c08110156104a257600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a66565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610520578181015183820152602001610508565b5050505090500194505050505060405180910390f35b61025a600480360360c081101561054c57600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561058b57600080fd5b82018360208201111561059d57600080fd5b803590602001918460208302840111600160201b831117156105be57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610bbd915050565b34801561060a57600080fd5b50610281610cb9565b6000606061062687878787876000610a66565b9199919850909650505050505050565b600061066c3330878960008151811061064b57fe5b60200260200101516001600160a01b0316610cc8909392919063ffffffff16565b61069c308760008151811061067d57fe5b60200260200101516001600160a01b0316610de790919063ffffffff16565b905060015b8651811015610807578681815181106106b657fe5b60200260200101516001600160a01b03168760018303815181106106d657fe5b60200260200101516001600160a01b031614156106f2576107ff565b6060845160405190808252806020026020018201604052801561071f578160200160208202803883390190505b50905060005b855181101561076d576001830360080286828151811061074157fe5b6020026020010151901c60ff1682828151811061075a57fe5b6020908102919091010152600101610725565b506107a488600184038151811061078057fe5b602002602001015189848151811061079457fe5b6020026020010151858488610e93565b6107b43089848151811061067d57fe5b92506107fc336107cd308b600187038151811061067d57fe5b8a60018603815181106107dc57fe5b60200260200101516001600160a01b0316610fe09092919063ffffffff16565b50505b6001016106a1565b50838110156108475760405162461bcd60e51b8152600401808060200182810382526035815260200180614c6a6035913960400191505060405180910390fd5b61085c33828860018a5103815181106107dc57fe5b5095945050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156108aa578160200160208202803883390190505b50935060015b8951811015610a59578981815181106108c557fe5b60200260200101516001600160a01b03168a60018303815181106108e557fe5b60200260200101516001600160a01b0316141561090157610a51565b60608a905061097581600184038151811061091857fe5b602002602001015182848151811061092c57fe5b6020026020010151846001146109585788600286038151811061094b57fe5b602002602001015161095a565b8c5b8c8c8c888151811061096857fe5b6020026020010151610a66565b88600186038151811061098457fe5b60209081029190910101929092529a5092506109a6858b63ffffffff61105e16565b94508351600014156109e15782516040519080825280602002602001820160405280156109dd578160200160208202803883390190505b5093505b60005b8451811015610a4e57610a2f60018403600802858381518110610a0357fe5b6020026020010151901b868381518110610a1957fe5b602002602001015161105e90919063ffffffff16565b858281518110610a3b57fe5b60209081029190910101526001016109e4565b50505b6001016108b0565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610ad957600080fd5b505afa158015610aed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610b1657600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610b4057600080fd5b908301906020820185811115610b5557600080fd5b82518660208202830111600160201b82111715610b7157600080fd5b82525081516020918201928201910280838360005b83811015610b9e578181015183820152602001610b86565b5050505090500160405250505092509250925096509650969350505050565b6000610bda6001600160a01b03881633308863ffffffff610cc816565b6000610bf56001600160a01b0389163063ffffffff610de716565b9050610c048888838787610e93565b610c1d6001600160a01b0388163063ffffffff610de716565b915084821015610c5e5760405162461bcd60e51b8152600401808060200182810382526035815260200180614c6a6035913960400191505060405180910390fd5b610c786001600160a01b038816338463ffffffff610fe016565b50610cad33610c966001600160a01b038b163063ffffffff610de716565b6001600160a01b038b16919063ffffffff610fe016565b50509695505050505050565b6000546001600160a01b031681565b80610cd257610de1565b610cdb846110b8565b15610dc6576001600160a01b03831633148015610cf85750803410155b610d335760405162461bcd60e51b815260040180806020018281038252602b815260200180614cbf602b913960400191505060405180910390fd5b6001600160a01b0382163014610d7b576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610d79573d6000803e3d6000fd5b505b80341115610dc157336108fc610d97348463ffffffff6110f416565b6040518115909202916000818181858888f19350505050158015610dbf573d6000803e3d6000fd5b505b610de1565b610de16001600160a01b03851684848463ffffffff61113616565b50505050565b6000610df2836110b8565b15610e0857506001600160a01b03811631610e8d565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610e5e57600080fd5b505afa158015610e72573d6000803e3d6000fd5b505050506040513d6020811015610e8857600080fd5b505190505b92915050565b6000610e9e82611190565b90506001600160a01b03811615801590610ebf5750610ebd8682611373565b155b8015610ed25750610ed08186611373565b155b15610fca5760608351604051908082528060200260200182016040528015610f04578160200160208202803883390190505b50905060005b8451811015610f4957848181518110610f1f57fe5b602002602001015160ff16828281518110610f3657fe5b6020908102919091010152600101610f0a565b50610f5787838784876113b8565b60005b8451811015610f9d576008858281518110610f7157fe5b6020026020010151901c60ff16828281518110610f8a57fe5b6020908102919091010152600101610f5a565b50610fc38287610fbc6001600160a01b0383163063ffffffff610de716565b84876113b8565b5050610fd9565b610fd786868686866113b8565b505b5050505050565b600081610fef57506001611057565b610ff8846110b8565b15611039576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611033573d6000803e3d6000fd5b50611057565b6110536001600160a01b038516848463ffffffff6113c516565b5060015b9392505050565b600082820183811015611057576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60006001600160a01b03821615806110ec57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b600061105783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061141c565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610de19085906114b3565b600061119a614c2b565b604051806101000160405280610200815260200162010000815260200162020000815260200164040000000081526020016408000000008152602001641000000000815260200164200000000081526020016701000000000000008152509050611202614c2b565b50604080516101008101825273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8152600080516020614c9f833981519152602082015273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489181019190915273dac17f958d2ee523a2206206994597c13d831ec76060820152732260fac5e5542a773aa44fbcfedf7c193bc2c5996080820152731bbe271d15bb64df0bc6cd28df9ff322f2ebd84760a082015273eb4c2781e4eba804ce9a9803c67d0893436bb27d60c082015273c00e94cb662c3520282e6f5717214004a7f2688860e082015260005b600881101561136b576113048382600881106112f257fe5b6020020151869063ffffffff61166b16565b15611363576001600160a01b0384161561134f5760405162461bcd60e51b815260040180806020018281038252602e815260200180614cea602e913960400191505060405180910390fd5b81816008811061135b57fe5b602002015193505b6001016112da565b505050919050565b6000611387836001600160a01b03166110b8565b80156113a057506113a0826001600160a01b03166110b8565b806110575750506001600160a01b0391821691161490565b610fd98585858585611671565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526114179084906114b3565b505050565b600081848411156114ab5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611470578181015183820152602001611458565b50505050905090810190601f16801561149d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6114c5826001600160a01b03166119bf565b611516576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106115545780518252601f199092019160209182019101611535565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146115b6576040519150601f19603f3d011682016040523d82523d6000602084013e6115bb565b606091505b509150915081611612576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115610de15780806020019051602081101561162e57600080fd5b5051610de15760405162461bcd60e51b815260040180806020018281038252602a815260200180614d18602a913960400191505060405180910390fd5b16151590565b836001600160a01b0316856001600160a01b0316141561169057610fd9565b6116a6816508000000000063ffffffff61166b16565b15156116bc82634000000063ffffffff61166b16565b151514156119b25760006116cf866119fb565b90506001600160a01b038082161461185757856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561172757600080fd5b505af115801561173b573d6000803e3d6000fd5b505050506040513d602081101561175157600080fd5b506000905061176f6001600160a01b0383163063ffffffff610de716565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156118095773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156117f057600080fd5b505af1158015611804573d6000803e3d6000fd5b505050505b6118556001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214611836578261184c565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b87838787611671565b505b611860856119fb565b90506001600160a01b03808216146119b0576118be866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146118a057826118b6565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686611b2f565b6000611919306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146118ee5783611904565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff610de716565b90505b6119366001600160a01b038316878363ffffffff611b3c16565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b505050506040513d60208110156119a657600080fd5b50610fd992505050565b505b610fd98585858585611b2f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906119f357508115155b949350505050565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b60208310611a895780518252601f199092019160209182019101611a6a565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114611ae9576040519150601f19603f3d011682016040523d82523d6000602084013e611aee565b606091505b5091509150811580611aff57508051155b15611b1057600019925050506110ef565b808060200190516020811015611b2557600080fd5b5051949350505050565b610fd98585858585611c30565b611b45836110b8565b6114175780611b6e57611b696001600160a01b03841683600063ffffffff611f7916565b611417565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611bbf57600080fd5b505afa158015611bd3573d6000803e3d6000fd5b505050506040513d6020811015611be957600080fd5b5051905081811015610de1578015611c1657611c166001600160a01b03851684600063ffffffff611f7916565b610de16001600160a01b038516848463ffffffff611f7916565b836001600160a01b0316856001600160a01b03161415611c4f57610fd9565b611c62816208000063ffffffff61166b16565b1515611c7882634000000063ffffffff61166b16565b15151415611f6c576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611da657604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611cfe57600080fd5b505afa158015611d12573d6000803e3d6000fd5b505050506040513d6020811015611d2857600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015611d6857600080fd5b505af1158015611d7c573d6000803e3d6000fd5b50505050611da173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8585858561208c565b610fd9565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611e2457604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611cfe57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611ed757611e6a8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611c30565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611eb957600080fd5b505af1158015611ecd573d6000803e3d6000fd5b5050505050610fd9565b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611f6c57611f1d8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611c30565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611eb957600080fd5b610fd9858585858561208c565b801580611fff575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611fd157600080fd5b505afa158015611fe5573d6000803e3d6000fd5b505050506040513d6020811015611ffb57600080fd5b5051155b61203a5760405162461bcd60e51b8152600401808060200182810382526036815260200180614d426036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526114179084906114b3565b610fd985858585855b6120a8816280000063ffffffff61166b16565b156120bd82634000000063ffffffff61166b16565b15141561250f576120cc614c2b565b6120d461251c565b905060005b60088110156122a7578181600881106120ee57fe5b60200201516001600160a01b0316876001600160a01b0316141561229f57600082826008811061211a57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561215757600080fd5b505afa15801561216b573d6000803e3d6000fd5b505050506040513d602081101561218157600080fd5b50519050600083836008811061219357fe5b60200201516001600160a01b031663c85c93aa88600160006040519080825280602002602001820160405280156121d4578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561223457818101518382015260200161221c565b50505050905001945050505050602060405180830381600087803b15801561225b57600080fd5b505af115801561226f573d6000803e3d6000fd5b505050506040513d602081101561228557600080fd5b505190506122968289838989612095565b50505050610fd9565b6001016120d9565b5060005b600881101561250c578181600881106122c057fe5b60200201516001600160a01b0316866001600160a01b031614156125045760008282600881106122ec57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561232957600080fd5b505afa15801561233d573d6000803e3d6000fd5b505050506040513d602081101561235357600080fd5b505190506123648882888888612602565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156123ae57600080fd5b505afa1580156123c2573d6000803e3d6000fd5b505050506040513d60208110156123d857600080fd5b505190506124078484600881106123eb57fe5b60200201516001600160a01b038416908363ffffffff611b3c16565b83836008811061241357fe5b60200201516001600160a01b0316633cfcef64826000604051908082528060200260200182016040528015612452578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156124a8578181015183820152602001612490565b505050509050019350505050602060405180830381600087803b1580156124ce57600080fd5b505af11580156124e2573d6000803e3d6000fd5b505050506040513d60208110156124f857600080fd5b50610fd9945050505050565b6001016122ab565b50505b610fd98585858585612602565b612524614c2b565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b610fd985858585855b836001600160a01b0316856001600160a01b0316141561262a57610fd9565b61263c8161080063ffffffff61166b16565b151561265282634000000063ffffffff61166b16565b151514156129ed57612662614c4a565b61266a6129fa565b905060005b600d811015612827578181600d811061268457fe5b60200201516001600160a01b0316876001600160a01b0316141561281f5760008282600d81106126b057fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126ed57600080fd5b505afa158015612701573d6000803e3d6000fd5b505050506040513d602081101561271757600080fd5b505190508282600d811061272757fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561277157600080fd5b505af1158015612785573d6000803e3d6000fd5b505050506128178188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156127e457600080fd5b505afa1580156127f8573d6000803e3d6000fd5b505050506040513d602081101561280e57600080fd5b5051888861260b565b505050610fd9565b60010161266f565b5060005b600d8110156129ea578181600d811061284057fe5b60200201516001600160a01b0316866001600160a01b031614156129e25760008282600d811061286c57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128a957600080fd5b505afa1580156128bd573d6000803e3d6000fd5b505050506040513d60208110156128d357600080fd5b505190506128e48882888888612b67565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561292e57600080fd5b505afa158015612942573d6000803e3d6000fd5b505050506040513d602081101561295857600080fd5b5051905061296b8484600d81106123eb57fe5b8383600d811061297757fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156129c157600080fd5b505af11580156129d5573d6000803e3d6000fd5b5050505050505050610fd9565b60010161282b565b50505b610fd98585858585612b67565b612a02614c4a565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b610fd985858585855b836001600160a01b0316856001600160a01b03161415612b8f57610fd9565b612ba081601063ffffffff61166b16565b1515612bb682634000000063ffffffff61166b16565b15151415612d43576000612bc986612d50565b90506001600160a01b0380821614612c7857856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612c2157600080fd5b505af1158015612c35573d6000803e3d6000fd5b505050506040513d6020811015612c4b57600080fd5b5060009050612c696001600160a01b0383163063ffffffff610de716565b9050610fc38287838787612b70565b612c8185612d50565b90506001600160a01b0380821614612d4157612ca08682868686612f42565b6000612cbb6001600160a01b0383163063ffffffff610de716565b9050612ccf826001600160a01b03166110b8565b1561191c57734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612d2357600080fd5b505af1158015612d37573d6000803e3d6000fd5b5050505050610fc3565b505b610fd98585858585612f42565b60006001600160a01b038216734ddc2d193948926d02f9b1fe9e1daa0718270ed51415612d7f575060006110ef565b6001600160a01b038216735d3a536e4d6dbd6114cc1ead35777bab948e36431415612db95750600080516020614c9f8339815191526110ef565b6001600160a01b038216736c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e1415612df95750730d8775f648430679a709e98d2b0cb6250d2887ef6110ef565b6001600160a01b03821673158079ee67fce2f58472a96584a73c7ab9ac95c11415612e395750731985365e9f78359a9b6ad760e32412f4a445e8626110ef565b6001600160a01b0382167339aa39c021dfbae8fac545936693ac917d5e75631415612e79575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486110ef565b6001600160a01b03821673c11b1268c1a384e55c48c2391d8d480264a3a7f41415612eb95750732260fac5e5542a773aa44fbcfedf7c193bc2c5996110ef565b6001600160a01b03821673b3319f5d18bc0d84dd1b4825dcde5d5f7266d4071415612ef9575073e41d2489571d322189246dafa5ebde1f4699f4986110ef565b6001600160a01b03821673f650c3d88d12db855b8bf7d11be6c55a4e07dcc91415612f39575073dac17f958d2ee523a2206206994597c13d831ec76110ef565b50600019919050565b610fd98585858585836001600160a01b0316856001600160a01b03161415612f6957610fd9565b612f7a81602063ffffffff61166b16565b1515612f9082634000000063ffffffff61166b16565b15151415613237576000612fa386613244565b90506001600160a01b03808216146130f357612fc7816001600160a01b03166110b8565b1561304d576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b15801561301b57600080fd5b505af115801561302f573d6000803e3d6000fd5b505050506040513d602081101561304557600080fd5b506130c99050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b15801561309c57600080fd5b505af11580156130b0573d6000803e3d6000fd5b505050506040513d60208110156130c657600080fd5b50505b60006130e46001600160a01b0383163063ffffffff610de716565b9050610fc382878387876135ba565b6130fc85613244565b90506001600160a01b03808216146132355761311b86828686866135ba565b60006131366001600160a01b0383163063ffffffff610de716565b905061314a826001600160a01b03166110b8565b156131cc5760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b15801561319957600080fd5b505af11580156131ad573d6000803e3d6000fd5b50505050506040513d60208110156131c457600080fd5b50610fc39050565b6131e66001600160a01b038316878363ffffffff611b3c16565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b15801561197c57600080fd5b505b610fd985858585856135ba565b6000613258826001600160a01b03166110b8565b1561326657506000196110ef565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b602083106132d15780518252601f1990920191602091820191016132b2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613332576040519150601f19603f3d011682016040523d82523d6000602084013e613337565b606091505b50915091508161334d57600019925050506110ef565b6000805b82518160060110156134a65782816000018151811061336c57fe5b6020910101516001600160f81b031916602360f91b1480156133af575082816001018151811061339857fe5b6020910101516001600160f81b031916607560f81b145b80156133dc57508281600201815181106133c557fe5b6020910101516001600160f81b031916601b60fa1b145b801561340957508281600301815181106133f257fe5b6020910101516001600160f81b031916606360f81b145b8015613436575082816004018151811061341f57fe5b6020910101516001600160f81b031916603960f91b145b8015613463575082816005018151811061344c57fe5b6020910101516001600160f81b031916607560f81b145b8015613490575082816006018151811061347957fe5b6020910101516001600160f81b031916606d60f81b145b1561349e57600191506134a6565b600101613351565b50806134b95760001993505050506110ef565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b6020831061351c5780518252601f1990920191602091820191016134fd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d806000811461357d576040519150601f19603f3d011682016040523d82523d6000602084013e613582565b606091505b5090935091508261359a5760001993505050506110ef565b8180602001905160208110156135af57600080fd5b505195945050505050565b610fd985858585855b836001600160a01b0316856001600160a01b031614156135e257610fd9565b6135f381608063ffffffff61166b16565b151561360982634000000063ffffffff61166b16565b1515141561385957600061361c86613866565b90506001600160a01b038082161461369f57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561367457600080fd5b505af1158015613688573d6000803e3d6000fd5b5050505061369981868686866135c3565b50610fd9565b6136a885613866565b90506001600160a01b0380821614613857576136c78682868686613c8a565b60006136e26001600160a01b0383163063ffffffff610de716565b905061377773398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b15801561373457600080fd5b505afa158015613748573d6000803e3d6000fd5b505050506040513d602081101561375e57600080fd5b50516001600160a01b038416908363ffffffff611b3c16565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666137a36001600160a01b0385166110b8565b6137ae5760006137b0565b825b6137c2856001600160a01b03166110b8565b6137cc57846137e2565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b15801561383757600080fd5b505af115801561384b573d6000803e3d6000fd5b50505050505050610fd9565b505b610fd98585858585613c8a565b60006001600160a01b038216733a3a65aab0dd2a17e3f1947ba16138cd37d08c041415613895575060006110ef565b6001600160a01b03821673fc1e690f61efd961294b3e1ce3313fbd8aa4f85d14156138cf5750600080516020614c9f8339815191526110ef565b6001600160a01b038216739ba00d6856a4edf4665bca2c2309936572473b7e141561390f575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486110ef565b6001600160a01b03821673625ae63000f46200499120b906716420bd059240141561394f57507357ab1ec28d129707052df4df418d58a2d46d5f516110ef565b6001600160a01b038216736ee0f7bb50a54ab5253da0667b0dc2ee526c30a8141561398f5750734fabb145d64652a948d72533023f6e7a623c7c536110ef565b6001600160a01b038216734da9b813057d04baef4e5800e36083717b4a034114156139ca57506e085d4780b73119b644ae5ecd22b3766110ef565b6001600160a01b0382167371fc860f7d3a592a4a98740e39db31d25db65ae81415613a0a575073dac17f958d2ee523a2206206994597c13d831ec76110ef565b6001600160a01b03821673e1ba0fb44ccb0d11b80f92f4f8ed94ca3ff51d001415613a4a5750730d8775f648430679a709e98d2b0cb6250d2887ef6110ef565b6001600160a01b038216739d91be44c06d373a8a226e1f3b146956083803eb1415613a8a575073dd974d5c2e2928dea5f71b9825b8b646686bd2006110ef565b6001600160a01b038216737d2d3688df45ce7c552e19c27e007673da9204b81415613aca57507380fb784b7ed66730e8b1dbd9820afd29931aab036110ef565b6001600160a01b03821673a64bd6c70cb9051f6a9ba1f163fdc07e0dfb5f841415613b0a575073514910771af9ca656af840dff83e8264ecf986ca6110ef565b6001600160a01b038216736fce4a401b6b80ace52baaefe4421bd188e76f6f1415613b4a5750730f5d2fb29fb7d3cfee444a200298f468908cc9426110ef565b6001600160a01b038216737deb5e830be29f91e298ba5ff1356bb7f81469981415613b8a5750739f8f72aa9304c8b593d555f12ef6589cc3a579a26110ef565b6001600160a01b0382167371010a9d003445ac60c4e6a7017c1e89a477b4381415613bca5750731985365e9f78359a9b6ad760e32412f4a445e8626110ef565b6001600160a01b03821673328c4c80bc7aca0834db37e6600a6c49e12da4de1415613c0a575073c011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f6110ef565b6001600160a01b03821673fc4b8ed459e00e5400be803a9bb3954234fd50e31415613c4a5750732260fac5e5542a773aa44fbcfedf7c193bc2c5996110ef565b6001600160a01b038216736fb0855c404e09c47c3fbca25f08d4e41f9f062f1415612f39575073e41d2489571d322189246dafa5ebde1f4699f4986110ef565b836001600160a01b0316856001600160a01b03161415613ca957610fd9565b613cbb8161040063ffffffff61166b16565b1515613cd182634000000063ffffffff61166b16565b15151415613fa8576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613e5e57736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613d5857600080fd5b505af1158015613d6c573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b158015613dc557600080fd5b505afa158015613dd9573d6000803e3d6000fd5b505050506040513d6020811015613def57600080fd5b505190508015613e43576060613e1d73b683d83a532e2cb7dfa5275eed3698436371cc9f8784600187610613565b915050613e4173b683d83a532e2cb7dfa5275eed3698436371cc9f87848487610e93565b505b613699600080516020614c9f83398151915286868686613fb1565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613fa857613e9e85600080516020614c9f833981519152858585613fb1565b604080516370a0823160e01b81523060048201529051600091600080516020614c9f833981519152916370a0823191602480820192602092909190829003018186803b158015613eed57600080fd5b505afa158015613f01573d6000803e3d6000fd5b505050506040513d6020811015613f1757600080fd5b50519050613f4e600080516020614c9f833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff611b3c16565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611eb957600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b03161415613fd057610fd9565b613fe181604063ffffffff61166b16565b1515613ff782634000000063ffffffff61166b16565b15151415614265576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c215141561411c576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b15801561407d57600080fd5b505af1158015614091573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051611da19350600080516020614c9f8339815191529250879183916370a0823191602480820192602092909190829003018186803b1580156140e957600080fd5b505afa1580156140fd573d6000803e3d6000fd5b505050506040513d602081101561411357600080fd5b5051858561426e565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c21514156142655761415c85600080516020614c9f83398151915285858561426e565b604080516370a0823160e01b81523060048201529051600091600080516020614c9f833981519152916370a0823191602480820192602092909190829003018186803b1580156141ab57600080fd5b505afa1580156141bf573d6000803e3d6000fd5b505050506040513d60208110156141d557600080fd5b5051905061420c600080516020614c9f8339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff611b3c16565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611eb957600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b0316141561428d57610fd9565b6142a3816502000000000063ffffffff61166b16565b15156142b982634000000063ffffffff61166b16565b15151415614ab9576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a514156147fc576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48148061432757506001600160a01b038416600080516020614c9f833981519152145b8061434e57506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b8061437057506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b156145705760408051633b3fb85360e21b81526001600160a01b03878116600483015260248201869052861660448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b1580156143e157600080fd5b505afa1580156143f5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561441e57600080fd5b815160208301805160405192949293830192919084600160201b82111561444457600080fd5b90830190602082018581111561445957600080fd5b8251600160201b81118282018810171561447257600080fd5b82525081516020918201929091019080838360005b8381101561449f578181015183820152602001614487565b50505050905090810190601f1680156144cc5780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b83526001600160a01b038d16600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b15801561453d57600080fd5b505af1158015614551573d6000803e3d6000fd5b505050506040513d602081101561456757600080fd5b50611da1915050565b60408051633b3fb85360e21b81526001600160a01b038716600482015260248101859052600080516020614c9f83398151915260448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b1580156145e857600080fd5b505afa1580156145fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561462557600080fd5b815160208301805160405192949293830192919084600160201b82111561464b57600080fd5b90830190602082018581111561466057600080fd5b8251600160201b81118282018810171561467957600080fd5b82525081516020918201929091019080838360005b838110156146a657818101518382015260200161468e565b50505050905090810190601f1680156146d35780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b8352600080516020614c9f833981519152600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b15801561474957600080fd5b505af115801561475d573d6000803e3d6000fd5b505050506040513d602081101561477357600080fd5b5050604080516370a0823160e01b8152306004820152905161369991600080516020614c9f83398151915291889183916370a0823191602480820192602092909190829003018186803b1580156147c957600080fd5b505afa1580156147dd573d6000803e3d6000fd5b505050506040513d60208110156147f357600080fd5b50518686614ac2565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415614ab9576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48148061486257506001600160a01b038516600080516020614c9f833981519152145b8061488957506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b806148ab57506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b15614981576148de6001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff611b3c16565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b15801561494f57600080fd5b505af1158015614963573d6000803e3d6000fd5b505050506040513d602081101561497957600080fd5b50611da19050565b61499c85600080516020614c9f833981519152858585614ac2565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c91600080516020614c9f83398151915291889183916370a08231916024808301926020929190829003018186803b158015614a0757600080fd5b505afa158015614a1b573d6000803e3d6000fd5b505050506040513d6020811015614a3157600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b158015614a8f57600080fd5b505af1158015614aa3573d6000803e3d6000fd5b505050506040513d6020811015610fc357600080fd5b610fd985858585855b836001600160a01b0316856001600160a01b03161415614ae157610fd9565b610fd98585858585600154614b09906001600160a01b0387811691168563ffffffff611b3c16565b6001546001600160a01b039081169063e2a7515e90614b299088166110b8565b614b34576000614b36565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015614bce578181015183820152602001614bb6565b505050509050019750505050505050506020604051808303818588803b158015614bf757600080fd5b505af1158015614c0b573d6000803e3d6000fd5b50505050506040513d6020811015614c2257600080fd5b50505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28294f6e6553706c69743a20446f206e6f7420757365206d756c74697061746820776974682065616368206f746865725361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a72315820293752088a2aec2583d287e39911b8b86603464ae8a1e18961dd33188fb9876664736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002fdac0084b40d7c259a284d72e8ee43930262266000000000000000000000000712e990ffb170bfe8c0de8b4f25918589a80babe
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x2Fdac0084B40D7C259a284d72e8eE43930262266
Arg [1] : _oneSplit (address): 0x712E990ffB170BFe8C0de8B4f25918589a80bAbE
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002fdac0084b40d7c259a284d72e8ee43930262266
Arg [1] : 000000000000000000000000712e990ffb170bfe8c0de8b4f25918589a80babe
Deployed Bytecode Sourcemap
189948:5842:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;190588:10;190602:9;190588:23;;190580:32;;;;;;189948:5842;190628:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190628:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;190628: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;190628:515:0;;;;;;;;;;;;;;;;;;194033:1290;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;194033:1290:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;194033:1290:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;194033:1290:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;194033:1290:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;194033:1290:0;;;;;;;;;;;;-1:-1:-1;194033:1290:0;-1:-1:-1;194033:1290:0;;;;-1:-1:-1;194033:1290:0;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;194033:1290:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;194033:1290:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;194033:1290:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;194033:1290:0;;-1:-1:-1;;194033:1290:0;;;-1:-1:-1;194033:1290:0;;-1:-1:-1;;194033:1290:0:i;:::-;;;;;;;;;;;;;;;;190293:25;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190293:25:0;;;:::i;:::-;;;;-1:-1:-1;;;;;190293:25:0;;;;;;;;;;;;;;191786:1433;;8:9:-1;5:2;;;30:1;27;20:12;5:2;191786:1433:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;191786:1433:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;191786:1433:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;191786:1433:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;191786:1433:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;191786:1433:0;;;;;;;;;;;;;;;-1:-1:-1;191786:1433:0;;-1:-1:-1;191786:1433:0;-1:-1:-1;191786:1433:0;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;191786:1433:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;191786:1433:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;191786:1433:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;191786:1433:0;;-1:-1:-1;191786:1433:0;;-1:-1:-1;;;;;191786:1433: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;191786:1433: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;191786:1433:0;;;;;;;;;;;;;;;;;;;;191151:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;191151:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;191151:627:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;191151:627:0;;;;;;;;;;;;;;;;;;;193227:798;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;193227:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;193227:798:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;193227:798:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;193227:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;193227:798:0;;-1:-1:-1;;193227:798:0;;;-1:-1:-1;193227:798:0;;-1:-1:-1;;193227:798:0:i;190253:33::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190253:33:0;;;:::i;190628:515::-;190850:20;190885:29;190975:160;191014:9;191038;191062:6;191083:5;191103;191123:1;190975:24;:160::i;:::-;190942:193;;;;-1:-1:-1;190628:515:0;;-1:-1:-1;;;;;;;190628:515:0:o;194033:1290::-;194232:20;194265:66;194297:10;194317:4;194324:6;194265;194272:1;194265:9;;;;;;;;;;;;;;-1:-1:-1;;;;;194265:31:0;;;:66;;;;;;:::i;:::-;194359:43;194396:4;194359:6;194366:1;194359:9;;;;;;;;;;;;;;-1:-1:-1;;;;;194359:28:0;;;:43;;;;:::i;:::-;194344:58;-1:-1:-1;194427:1:0;194413:719;194434:6;:13;194430:1;:17;194413:719;;;194490:6;194497:1;194490:9;;;;;;;;;;;;;;-1:-1:-1;;;;;194473:26:0;:6;194484:1;194480;:5;194473:13;;;;;;;;;;;;;;-1:-1:-1;;;;;194473:26:0;;194469:75;;;194520:8;;194469:75;194560:21;194598:12;:19;194584:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;194584:34:0;-1:-1:-1;194560:58:0;-1:-1:-1;194638:6:0;194633:133;194654:12;:19;194650:1;:23;194633:133;;;194739:1;194735;:5;194730:1;:11;194710:12;194723:1;194710:15;;;;;;;;;;;;;;:32;;194746:4;194709:41;194699:4;194704:1;194699:7;;;;;;;;;;;;;;;;;:51;194675:3;;194633:133;;;;194782:158;194806:6;194817:1;194813;:5;194806:13;;;;;;;;;;;;;;194838:6;194845:1;194838:9;;;;;;;;;;;;;;194866:12;194897:4;194920:5;194782;:158::i;:::-;194970:43;195007:4;194970:6;194977:1;194970:9;;;;;;;:43;194955:58;;195028:92;195060:10;195072:47;195113:4;195072:6;195083:1;195079;:5;195072:13;;;;;;;:47;195028:6;195039:1;195035;:5;195028:13;;;;;;;;;;;;;;-1:-1:-1;;;;;195028:31:0;;;:92;;;;;:::i;:::-;;194413:719;;194449:3;;194413:719;;;;195168:9;195152:12;:25;;195144:91;;;;-1:-1:-1;;;195144:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;195246:69;195290:10;195302:12;195246:6;195269:1;195253:6;:13;:17;195246:25;;;;;;;:69;;194033:1290;;;;;;;:::o;190293:25::-;;;-1:-1:-1;;;;;190293:25:0;;:::o;191786:1433::-;192058:30;192103:25;192143:29;192200:21;192280:1;192264:6;:13;:17;192250:32;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;192250:32:0;-1:-1:-1;192234:48:0;-1:-1:-1;192307:1:0;192293:919;192314:6;:13;192310:1;:17;192293:919;;;192370:6;192377:1;192370:9;;;;;;;;;;;;;;-1:-1:-1;;;;;192353:26:0;:6;192364:1;192360;:5;192353:13;;;;;;;;;;;;;;-1:-1:-1;;;;;192353:26:0;;192349:75;;;192400:8;;192349:75;192440:23;192466:6;192440:32;;192594:261;192637:7;192649:1;192645;:5;192637:14;;;;;;;;;;;;;;192670:7;192678:1;192670:10;;;;;;;;;;;;;;192700:1;192705;192700:6;192699:40;;192719:13;192737:1;192733;:5;192719:20;;;;;;;;;;;;;;192699:40;;;192710:6;192699:40;192758:5;192782;192806:31;192838:1;192806:34;;;;;;;;;;;;;;192594:24;:261::i;:::-;192508:13;192526:1;192522;:5;192508:20;;;;;;;;;;;;;;;;;192489:366;;;;;-1:-1:-1;192489:366:0;-1:-1:-1;192890:29:0;:17;192489:366;192890:29;:21;:29;:::i;:::-;192870:49;;192940:12;:19;192963:1;192940:24;192936:106;;;193014:4;:11;193000:26;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;193000:26:0;;192985:41;;192936:106;193061:6;193056:145;193077:12;:19;193073:1;:23;193056:145;;;193140:45;193181:1;193177;:5;193172:1;:11;193160:4;193165:1;193160:7;;;;;;;;;;;;;;:24;;193140:12;193153:1;193140:15;;;;;;;;;;;;;;:19;;:45;;;;:::i;:::-;193122:12;193135:1;193122:15;;;;;;;;;;;;;;;;;:63;193098:3;;193056:145;;;;192293:919;;192329:3;;192293:919;;;;191786:1433;;;;;;;;;;:::o;191151:627::-;191429:20;191568:12;;:202;;;-1:-1:-1;;;191568:202:0;;-1:-1:-1;;;;;191568:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;191429:20;;191504:29;;191568:12;;:37;;:202;;;;;191429:20;;191568:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;191568:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;191568:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;191568: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;191568: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;191568:202:0;;421:4:-1;412:14;;;;191568:202:0;;;;;412:14:-1;191568: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;191568:202:0;;;;;;;;;;;191561:209;;;;;;191151:627;;;;;;;;;;:::o;193227:798::-;193442:20;193475:66;-1:-1:-1;;;;;193475:31:0;;193507:10;193527:4;193534:6;193475:66;:31;:66;:::i;:::-;193552:17;193572:43;-1:-1:-1;;;;;193572:28:0;;193609:4;193572:43;:28;:43;:::i;:::-;193552:63;;193626:59;193632:9;193643;193654;193665:12;193679:5;193626;:59::i;:::-;193713:43;-1:-1:-1;;;;;193713:28:0;;193750:4;193713:43;:28;:43;:::i;:::-;193698:58;;193791:9;193775:12;:25;;193767:91;;;;-1:-1:-1;;;193767:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;193869:53;-1:-1:-1;;;;;193869:27:0;;193897:10;193909:12;193869:53;:27;:53;:::i;:::-;-1:-1:-1;193933:84:0;193961:10;193973:43;-1:-1:-1;;;;;193973:28:0;;194010:4;193973:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;193933:27:0;;;:84;;:27;:84;:::i;:::-;;193227:798;;;;;;;;;:::o;190253:33::-;;;-1:-1:-1;;;;;190253:33:0;;:::o;35647:617::-;35758:11;35754:50;;35786:7;;35754:50;35820:12;35826:5;35820;:12::i;:::-;35816:441;;;-1:-1:-1;;;;;35857:18:0;;35865:10;35857:18;:41;;;;;35892:6;35879:9;:19;;35857:41;35849:97;;;;-1:-1:-1;;;35849:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;35965:19:0;;35979:4;35965:19;35961:97;;36005:37;;-1:-1:-1;;;;;36005:29:0;;;:37;;;;;36035:6;;36005:37;;;;36035:6;36005:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;36005:37:0;35961:97;36088:6;36076:9;:18;36072:101;;;36115:10;:42;36135:21;:9;36149:6;36135:21;:13;:21;:::i;:::-;36115:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;36115:42:0;36072:101;35816:441;;;36205:40;-1:-1:-1;;;;;36205:22:0;;36228:4;36234:2;36238:6;36205:40;:22;:40;:::i;:::-;35647:617;;;;:::o;37249:228::-;37327:7;37351:12;37357:5;37351;:12::i;:::-;37347:123;;;-1:-1:-1;;;;;;37387:11:0;;;37380:18;;37347:123;37438:5;-1:-1:-1;;;;;37438:15:0;;37454:3;37438:20;;;;;;;;;;;;;-1:-1:-1;;;;;37438:20:0;-1:-1:-1;;;;;37438:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;37438:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;37438:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37438:20:0;;-1:-1:-1;37347:123:0;37249:228;;;;:::o;126788:1245::-;126973:15;126991:25;127010:5;126991:18;:25::i;:::-;126973:43;-1:-1:-1;;;;;;127033:21:0;;;;;;:59;;;127059:33;127072:9;127083:8;127059:12;:33::i;:::-;127058:34;127033:59;:97;;;;;127097:33;127110:8;127120:9;127097:12;:33::i;:::-;127096:34;127033:97;127029:846;;;127147:21;127185:12;:19;127171:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;127171:34:0;-1:-1:-1;127147:58:0;-1:-1:-1;127225:6:0;127220:114;127241:12;:19;127237:1;:23;127220:114;;;127296:12;127309:1;127296:15;;;;;;;;;;;;;;127314:4;127296:22;127286:4;127291:1;127286:7;;;;;;;;;;;;;;;;;:32;127262:3;;127220:114;;;;127348:153;127378:9;127406:8;127433:6;127458:4;127481:5;127348:11;:153::i;:::-;127523:6;127518:121;127539:12;:19;127535:1;:23;127518:121;;;127614:1;127595:12;127608:1;127595:15;;;;;;;;;;;;;;:20;;127619:4;127594:29;127584:4;127589:1;127584:7;;;;;;;;;;;;;;;;;:39;127560:3;;127518:121;;;-1:-1:-1;127653:189:0;127683:8;127710:9;127738:42;-1:-1:-1;;;;;127738:27:0;;127774:4;127738:42;:27;:42;:::i;:::-;127799:4;127822:5;127653:11;:189::i;:::-;127857:7;;;;127029:846;127887:138;127913:9;127937;127961:6;127982:12;128009:5;127887:11;:138::i;:::-;126788:1245;;;;;;;:::o;35291:348::-;35377:4;35398:11;35394:55;;-1:-1:-1;35433:4:0;35426:11;;35394:55;35465:12;35471:5;35465;:12::i;:::-;35461:171;;;35494:37;;-1:-1:-1;;;;;35494:29:0;;;:37;;;;;35524:6;;35494:37;;;;35524:6;35494:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;35494:37:0;35461:171;;;35564:30;-1:-1:-1;;;;;35564:18:0;;35583:2;35587:6;35564:30;:18;:30;:::i;:::-;-1:-1:-1;35616:4:0;35461:171;35291:348;;;;;:::o;10785:181::-;10843:7;10875:5;;;10899:6;;;;10891:46;;;;;-1:-1:-1;;;10891:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;38067:166;38118:4;-1:-1:-1;;;;;38143:39:0;;;;:81;;-1:-1:-1;;;;;;38186:38:0;;35239:42;38186:38;38143:81;38135:90;;38067:166;;;;:::o;11241:136::-;11299:7;11326:43;11330:1;11333;11326:43;;;;;;;;;;;;;;;;;:3;:43::i;31946:204::-;32073:68;;;-1:-1:-1;;;;;32073:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;32073:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;32047:95:0;;32066:5;;32047:18;:95::i;123102:964::-;123167:15;123195:26;;:::i;:::-;:376;;;;;;;;4889:5;123195:376;;;;5362:7;123195:376;;;;5457:7;123195:376;;;;6867:11;123195:376;;;;6966:11;123195:376;;;;7065:12;123195:376;;;;7167:12;123195:376;;;;8728:17;123195:376;;;;;123584:29;;:::i;:::-;-1:-1:-1;123584:203:0;;;;;;;;45564:42;123584:203;;-1:-1:-1;;;;;;;;;;;123584:203:0;;;;46128:42;123584:203;;;;;;;46217:42;123584:203;;;;46752:42;123584:203;;;;46841:42;123584:203;;;;46663:42;123584:203;;;;47108:42;123584:203;;;;-1:-1:-1;123800:259:0;123821:15;123817:1;:19;123800:259;;;123862:24;123874:8;123883:1;123874:11;;;;;;;;;;;123862:5;;:24;:11;:24;:::i;:::-;123858:190;;;-1:-1:-1;;;;;123915:21:0;;;123907:80;;;;-1:-1:-1;;;123907:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;124017:12;124030:1;124017:15;;;;;;;;;;;124006:26;;123858:190;123838:3;;123800:259;;;;123102:964;;;;;:::o;57904:162::-;57978:4;58004:14;:6;-1:-1:-1;;;;;58004:12:0;;:14::i;:::-;:32;;;;;58022:14;:6;-1:-1:-1;;;;;58022:12:0;;:14::i;:::-;58003:54;;;-1:-1:-1;;;;;;;58041:16:0;;;;;;;57904:162::o;185103:328::-;185288:135;185311:9;185335;185359:6;185380:12;185407:5;185288:8;:135::i;31762:176::-;31871:58;;;-1:-1:-1;;;;;31871:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;31871:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;31845:85:0;;31864:5;;31845:18;:85::i;:::-;31762:176;;;:::o;11714:192::-;11800:7;11836:12;11828:6;;;;11820:29;;;;-1:-1:-1;;;11820:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;11820:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;11872:5:0;;;11714:192::o;33801:1114::-;34405:27;34413:5;-1:-1:-1;;;;;34405:25:0;;:27::i;:::-;34397:71;;;;;-1:-1:-1;;;34397:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;34542:12;34556:23;34591:5;-1:-1:-1;;;;;34583:19:0;34603:4;34583:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;34583:25:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;34541:67:0;;;;34627:7;34619:52;;;;;-1:-1:-1;;;34619:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34688:17;;:21;34684:224;;34830:10;34819:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;34819:30:0;34811:85;;;;-1:-1:-1;;;34811:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45059:117;45150:12;45149:19;;;45059:117::o;185439:1928::-;185643:9;-1:-1:-1;;;;;185630:22:0;:9;-1:-1:-1;;;;;185630:22:0;;185626:61;;;185669:7;;185626:61;185749:29;:5;7609:13;185749:29;:11;:29;:::i;:::-;185703:75;;:42;:5;6584:10;185703:42;:11;:42;:::i;:::-;:75;;;185699:1503;;;185795:17;185815:33;185838:9;185815:22;:33::i;:::-;185795:53;-1:-1:-1;;;;;;185867:24:0;;;;185863:533;;185925:9;-1:-1:-1;;;;;185912:31:0;;185944:6;185912:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;185912:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;185912:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;185970:15:0;;-1:-1:-1;185988:44:0;-1:-1:-1;;;;;185988:29:0;;186026:4;185988:44;:29;:44;:::i;:::-;185970:62;-1:-1:-1;;;;;;186055:18:0;;45776:42;186055:18;186051:89;;;45776:42;-1:-1:-1;;;;;186098:13:0;;186112:7;186098:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186098:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186098:22:0;;;;186051:89;186158:222;-1:-1:-1;;;;;186190:18:0;;45776:42;186190:18;186189:47;;186226:10;186189:47;;;45564:42;186189:47;186259:9;186291:7;186321:12;186356:5;186158:8;:222::i;:::-;185863:533;;186425:33;186448:9;186425:22;:33::i;:::-;186412:46;-1:-1:-1;;;;;;186477:24:0;;;;186473:718;;186522:224;186556:9;-1:-1:-1;;;;;186589:18:0;;45776:42;186589:18;186588:47;;186625:10;186588:47;;;45564:42;186588:47;186658:6;186687:12;186722:5;186522:11;:224::i;:::-;186767:24;186794:83;186871:4;-1:-1:-1;;;;;186796:18:0;;45776:42;186796:18;186795:47;;186832:10;186795:47;;;45564:42;186795:47;-1:-1:-1;;;;;186794:68:0;;:83;:68;:83;:::i;:::-;186767:110;;186896:103;187019:65;-1:-1:-1;;;;;187019:27:0;;187055:9;187067:16;187019:65;:27;:65;:::i;:::-;187116:9;-1:-1:-1;;;;;187103:29:0;;187133:16;187103:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;187103:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;187103:47:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;187169:7:0;;-1:-1:-1;;;187169:7:0;186473:718;185699:1503;;187221:138;187247:9;187271;187295:6;187316:12;187343:5;187221:11;:138::i;28791:619::-;28851:4;29319:20;;29162:66;29359:23;;;;;;:42;;-1:-1:-1;29386:15:0;;;29359:42;29351:51;28791:619;-1:-1:-1;;;;28791:619:0:o;181054:455::-;181226:128;;;-1:-1:-1;;;;;181226:128:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;181226:128:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;181177:188:0;;;;181122:6;;;;181156:17;;181002:42;;181226:128;;181177:188;;;;25:18:-1;181177: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;;;181177: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;;181141:224:0;;;;181383:7;181382:8;:28;;;-1:-1:-1;181394:11:0;;:16;181382:28;181378:78;;;-1:-1:-1;;181427:17:0;;;;;;181378:78;181486:4;181475:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;181475:26:0;;181054:455;-1:-1:-1;;;;181054:455:0:o;172499:329::-;172684:136;172708:9;172732;172756:6;172777:12;172804:5;172684:9;:136::i;36723:518::-;36816:12;36822:5;36816;:12::i;:::-;36811:423;;36849:11;36845:101;;36881:24;-1:-1:-1;;;;;36881:17:0;;36899:2;36903:1;36881:24;:17;:24;:::i;:::-;36924:7;;36845:101;36982:34;;;-1:-1:-1;;;36982:34:0;;37006:4;36982:34;;;;-1:-1:-1;;;;;36982:34:0;;;;;;;;;36962:17;;36982:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;36982:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;36982:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;36982:34:0;;-1:-1:-1;37035:18:0;;;37031:192;;;37078:13;;37074:86;;37116:24;-1:-1:-1;;;;;37116:17:0;;37134:2;37138:1;37116:24;:17;:24;:::i;:::-;37178:29;-1:-1:-1;;;;;37178:17:0;;37196:2;37200:6;37178:29;:17;:29;:::i;172836:1972::-;173041:9;-1:-1:-1;;;;;173028:22:0;:9;-1:-1:-1;;;;;173028:22:0;;173024:61;;;173067:7;;173024:61;173147:30;:5;5613:7;173147:30;:11;:30;:::i;:::-;173101:76;;:42;:5;6584:10;173101:42;:11;:42;:::i;:::-;:76;;;173097:1546;;;-1:-1:-1;;;;;173198:17:0;;45776:42;173198:17;173194:334;;;173250:29;;;-1:-1:-1;;;173250:29:0;;173273:4;173250:29;;;;;;45776:42;;173236:13;;45776:42;;173250:14;;:29;;;;;;;;;;;;;;45776:42;173250:29;;;5:2:-1;;;;30:1;27;20:12;5:2;173250:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;173250:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;173250:29:0;173236:44;;;-1:-1:-1;;;;;;173236:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;173236:44:0;;;;;;;-1:-1:-1;173236:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;173236:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;173236:44:0;;;;173299:188;45564:42;173367:9;173399:6;173428:12;173463:5;173299:11;:188::i;:::-;173506:7;;173194:334;-1:-1:-1;;;;;173548:29:0;;45689:42;173548:29;173544:370;;;173624:41;;;-1:-1:-1;;;173624:41:0;;173659:4;173624:41;;;;;;45689:42;;173598:25;;45689:42;;173624:26;;:41;;;;;;;;;;;;;;45689:42;173624:41;;;5:2:-1;;;;30:1;27;20:12;173544:370:0;-1:-1:-1;;;;;173934:17:0;;45776:42;173934:17;173930:331;;;173972:186;174004:9;45564:42;174070:6;174099:12;174134:5;173972:9;:186::i;:::-;45776:42;-1:-1:-1;;;;;174177:12:0;;174196:21;174177:43;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;174177:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;174177:43:0;;;;;174239:7;;173930:331;-1:-1:-1;;;;;174281:29:0;;45689:42;174281:29;174277:355;;;174331:186;174363:9;45564:42;174429:6;174458:12;174493:5;174331:9;:186::i;:::-;45689:42;-1:-1:-1;;;;;174536:24:0;;174567:21;174536:55;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;174277:355:0;174662:138;174688:9;174712;174736:6;174757:12;174784:5;174662:11;:138::i;32158:621::-;32528:10;;;32527:62;;-1:-1:-1;32544:39:0;;;-1:-1:-1;;;32544:39:0;;32568:4;32544:39;;;;-1:-1:-1;;;;;32544:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;32544:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;32544:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;32544:39:0;:44;32527:62;32519:152;;;;-1:-1:-1;;;32519:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32708:62;;;-1:-1:-1;;;;;32708:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;32708:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;32682:89:0;;32701:5;;32682:18;:89::i;160898:329::-;161083:136;161107:9;161131;161155:6;161176:12;161203:5;161235:1426;161476:30;:5;6082:8;161476:30;:11;:30;:::i;:::-;161475:31;161429:42;:5;6584:10;161429:42;:11;:42;:::i;:::-;161428:43;:78;161424:1148;;;161523:22;;:::i;:::-;161548:13;:11;:13::i;:::-;161523:38;-1:-1:-1;161583:6:0;161578:401;161599:13;161595:1;:17;161578:401;;;161662:6;161669:1;161662:9;;;;;;;;;;;-1:-1:-1;;;;;161642:30:0;:9;-1:-1:-1;;;;;161642:30:0;;161638:326;;;161697:17;161717:6;161724:1;161717:9;;;;;;;;;;;-1:-1:-1;;;;;161717:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;161717:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;161717:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;161717:17:0;;-1:-1:-1;161757:14:0;161774:6;161781:1;161774:9;;;;;;;;;;;-1:-1:-1;;;;;161774:25:0;;161800:6;161808:4;161828:1;161814:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;161814:16:0;;161774:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;161774:57:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;161774:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;161774:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;161774:57:0;;-1:-1:-1;161854:61:0;161864:10;161876:9;161774:57;161895:12;161909:5;161854:9;:61::i;:::-;161938:7;;;;;;161638:326;161614:3;;161578:401;;;-1:-1:-1;162000:6:0;161995:566;162016:13;162012:1;:17;161995:566;;;162079:6;162086:1;162079:9;;;;;;;;;;;-1:-1:-1;;;;;162059:30:0;:9;-1:-1:-1;;;;;162059:30:0;;162055:491;;;162114:17;162134:6;162141:1;162134:9;;;;;;;;;;;-1:-1:-1;;;;;162134:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;162134:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;162134:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;162134:17:0;;-1:-1:-1;162174:63:0;162186:9;162134:17;162209:6;162217:12;162231:5;162174:11;:63::i;:::-;162290:35;;;-1:-1:-1;;;162290:35:0;;162319:4;162290:35;;;;;;162262:25;;-1:-1:-1;;;;;162290:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;162290:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;162290:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;162290:35:0;;-1:-1:-1;162348:66:0;162384:6;162391:1;162384:9;;;;;;;;;;;-1:-1:-1;;;;;162348:27:0;;;162396:17;162348:66;:27;:66;:::i;:::-;162437:6;162444:1;162437:9;;;;;;;;;;;-1:-1:-1;;;;;162437:23:0;;162461:17;162494:1;162480:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;162480:16:0;;162437:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;162437:60:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;162437:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;162437:60:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;162520:7:0;;-1:-1:-1;;;;;162520:7:0;162055:491;162031:3;;161995:566;;;;161424:1148;;162591:62;162603:9;162614;162625:6;162633:12;162647:5;162591:11;:62::i;157041:716::-;157086:15;;:::i;:::-;-1:-1:-1;157181:568:0;;;;;;;;157228:42;157181:568;;157292:42;157181:568;;;;157356:42;157181:568;;;;;;;157420:42;157181:568;;;;157484:42;157181:568;;;;157548:42;157181:568;;;;157631:42;157181:568;;;;157695:42;157181:568;;;;157041:716;:::o;154581:330::-;154766:137;154791:9;154815;154839:6;154860:12;154887:5;154919:1465;155125:9;-1:-1:-1;;;;;155112:22:0;:9;-1:-1:-1;;;;;155112:22:0;;155108:61;;;155151:7;;155108:61;155231:31;:5;5031;155231:31;:11;:31;:::i;:::-;155185:77;;:42;:5;6584:10;155185:42;:11;:42;:::i;:::-;:77;;;155181:1114;;;155279:25;;:::i;:::-;155307:10;:8;:10::i;:::-;155279:38;-1:-1:-1;155339:6:0;155334:387;155355:14;155351:1;:18;155334:387;;;155419:7;155427:1;155419:10;;;;;;;;;;;-1:-1:-1;;;;;155399:31:0;:9;-1:-1:-1;;;;;155399:31:0;;155395:311;;;155455:17;155475:7;155483:1;155475:10;;;;;;;;;;;-1:-1:-1;;;;;155475:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155475:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155475:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;155475:18:0;;-1:-1:-1;155516:7:0;155524:1;155516:10;;;;;;;;;;;-1:-1:-1;;;;;155516:19:0;;155536:6;155516:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155516:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155516:27:0;;;;155566:91;155577:10;155589:9;155600:10;-1:-1:-1;;;;;155600:20:0;;155629:4;155600:35;;;;;;;;;;;;;-1:-1:-1;;;;;155600:35:0;-1:-1:-1;;;;;155600:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155600:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155600:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;155600:35:0;155637:12;155651:5;155566:10;:91::i;:::-;155680:7;;;;;155395:311;155371:3;;155334:387;;;-1:-1:-1;155742:6:0;155737:547;155758:14;155754:1;:18;155737:547;;;155822:7;155830:1;155822:10;;;;;;;;;;;-1:-1:-1;;;;;155802:31:0;:9;-1:-1:-1;;;;;155802:31:0;;155798:471;;;155858:17;155878:7;155886:1;155878:10;;;;;;;;;;;-1:-1:-1;;;;;155878:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;155878:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;155878:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;155878:18:0;;-1:-1:-1;155919:63:0;155931:9;155878:18;155954:6;155962:12;155976:5;155919:11;:63::i;:::-;156035:35;;;-1:-1:-1;;;156035:35:0;;156064:4;156035:35;;;;;;156007:25;;-1:-1:-1;;;;;156035:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;156035:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156035:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;156035:35:0;;-1:-1:-1;156093:67:0;156129:7;156137:1;156129:10;;;;;;156093:67;156183:7;156191:1;156183:10;;;;;;;;;;;-1:-1:-1;;;;;156183:18:0;;156202:17;156183:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;156183:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;156183:37:0;;;;156243:7;;;;;;155798:471;155774:3;;155737:547;;;;155181:1114;;156314:62;156326:9;156337;156348:6;156356:12;156370:5;156314:11;:62::i;150146:943::-;150188:17;;:::i;:::-;-1:-1:-1;150218:863:0;;;;;;;;150247:42;150218:863;;150312:42;150218:863;;;;150377:42;150218:863;;;;;;;150442:42;150218:863;;;;150507:42;150218:863;;;;150572:42;150218:863;;;;150637:42;150218:863;;;;150702:42;150218:863;;;;150767:42;150218:863;;;;150832:42;150218:863;;;;150897:42;150218:863;;;;150962:42;150218:863;;;;151027:42;150218:863;;;;150146:943;:::o;132643:333::-;132828:140;132856:9;132880;132904:6;132925:12;132952:5;132984:1813;133193:9;-1:-1:-1;;;;;133180:22:0;:9;-1:-1:-1;;;;;133180:22:0;;133176:61;;;133219:7;;133176:61;133299:34;:5;4584:4;133299:34;:11;:34;:::i;:::-;133253:80;;:42;:5;6584:10;133253:42;:11;:42;:::i;:::-;:80;;;133249:1383;;;133350:17;133370:38;133398:9;133370:27;:38::i;:::-;133350:58;-1:-1:-1;;;;;;133427:24:0;;;;133423:431;;133495:9;-1:-1:-1;;;;;133472:41:0;;133514:6;133472:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;133472:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;133472:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;133540:24:0;;-1:-1:-1;133567:44:0;-1:-1:-1;;;;;133567:29:0;;133605:4;133567:44;:29;:44;:::i;:::-;133540:71;;133639:199;133675:10;133708:9;133740:16;133779:12;133814:5;133639:13;:199::i;133423:431::-;133883:38;133911:9;133883:27;:38::i;:::-;133870:51;-1:-1:-1;;;;;;133940:24:0;;;;133936:685;;133985:187;134019:9;134051:10;134084:6;134113:12;134148:5;133985:11;:187::i;:::-;134193:24;134220:44;-1:-1:-1;;;;;134220:29:0;;134258:4;134220:44;:29;:44;:::i;:::-;134193:71;;134289:18;:10;-1:-1:-1;;;;;134289:16:0;;:18::i;:::-;134285:296;;;49268:42;-1:-1:-1;;;;;134332:9:0;;134348:16;134332:35;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;134332:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;134332:35:0;;;;;134285:296;;133936:685;133249:1383;;134651:138;134677:9;134701;134725:6;134746:12;134773:5;134651:11;:138::i;128153:1409::-;128226:6;-1:-1:-1;;;;;128249:59:0;;128265:42;128249:59;128245:115;;;-1:-1:-1;128346:1:0;128332:16;;128245:115;-1:-1:-1;;;;;128374:59:0;;128390:42;128374:59;128370:156;;;-1:-1:-1;;;;;;;;;;;;128457:57:0;;128370:156;-1:-1:-1;;;;;128540:59:0;;128556:42;128540:59;128536:156;;;-1:-1:-1;128637:42:0;128623:57;;128536:156;-1:-1:-1;;;;;128706:59:0;;128722:42;128706:59;128702:156;;;-1:-1:-1;128803:42:0;128789:57;;128702:156;-1:-1:-1;;;;;128872:59:0;;128888:42;128872:59;128868:157;;;-1:-1:-1;128970:42:0;128956:57;;128868:157;-1:-1:-1;;;;;129039:59:0;;129055:42;129039:59;129035:157;;;-1:-1:-1;129137:42:0;129123:57;;129035:157;-1:-1:-1;;;;;129206:59:0;;129222:42;129206:59;129202:156;;;-1:-1:-1;129303:42:0;129289:57;;129202:156;-1:-1:-1;;;;;129372:59:0;;129388:42;129372:59;129368:157;;;-1:-1:-1;129470:42:0;129456:57;;129368:157;-1:-1:-1;;;128153:1409:0;;;:::o;139824:332::-;140009:139;140036:9;140060;140084:6;140105:12;140132:5;140372:9;-1:-1:-1;;;;;140359:22:0;:9;-1:-1:-1;;;;;140359:22:0;;140355:61;;;140398:7;;140355:61;140478:33;:5;4644:4;140478:33;:11;:33;:::i;:::-;140432:79;;:42;:5;6584:10;140432:42;:11;:42;:::i;:::-;:79;;;140428:1618;;;140528:17;140548:26;140564:9;140548:15;:26::i;:::-;140528:46;-1:-1:-1;;;;;;140593:24:0;;;;140589:626;;140642:18;:10;-1:-1:-1;;;;;140642:16:0;;:18::i;:::-;140638:245;;;140685:68;;;-1:-1:-1;;;140685:68:0;;140739:4;140685:68;;;;;;;;;;;;-1:-1:-1;;;;;140685:45:0;;;;;:68;;;;;;;;;;;;;;-1:-1:-1;140685:45:0;:68;;;5:2:-1;;;;30:1;27;20:12;5:2;140685:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;140685:68:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;140638:245:0;;-1:-1:-1;140638:245:0;;140802:61;;;-1:-1:-1;;;140802:61:0;;140849:4;140802:61;;;;;;;;;;;;-1:-1:-1;;;;;140802:38:0;;;;;:61;;;;;;;;;;;;;;-1:-1:-1;140802:38:0;:61;;;5:2:-1;;;;30:1;27;20:12;5:2;140802:61:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;140802:61:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;140638:245:0;140903:24;140930:44;-1:-1:-1;;;;;140930:29:0;;140968:4;140930:44;:29;:44;:::i;:::-;140903:71;;141002:197;141036:10;141069:9;141101:16;141140:12;141175:5;141002:11;:197::i;140589:626::-;141244:26;141260:9;141244:15;:26::i;:::-;141231:39;-1:-1:-1;;;;;;141289:24:0;;;;141285:750;;141334:187;141368:9;141400:10;141433:6;141462:12;141497:5;141334:11;:187::i;:::-;141542:24;141569:44;-1:-1:-1;;;;;141569:29:0;;141607:4;141569:44;:29;:44;:::i;:::-;141542:71;;141638:18;:10;-1:-1:-1;;;;;141638:16:0;;:18::i;:::-;141634:361;;;141681:86;;;-1:-1:-1;;;141681:86:0;;141761:4;141681:86;;;;;;-1:-1:-1;;;;;141681:47:0;;;;;141735:16;;141681:86;;;;;;;;;;;;;;;141735:16;141681:47;:86;;;5:2:-1;;;;30:1;27;20:12;5:2;141681:86:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;141681:86:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;141634:361:0;;-1:-1:-1;141634:361:0;;141816:65;-1:-1:-1;;;;;141816:27:0;;141852:9;141864:16;141816:65;:27;:65;:::i;:::-;141904:71;;;-1:-1:-1;;;141904:71:0;;141951:4;141904:71;;;;;;;;;;;;-1:-1:-1;;;;;141904:38:0;;;;;:71;;;;;;;;;;;;;;-1:-1:-1;141904:38:0;:71;;;5:2:-1;;;;30:1;27;20:12;141285:750:0;140428:1618;;142065:138;142091:9;142115;142139:6;142160:12;142187:5;142065:11;:138::i;135625:1173::-;135686:6;135709:13;:5;-1:-1:-1;;;;;135709:11:0;;:13::i;:::-;135705:63;;;-1:-1:-1;;;135739:17:0;;135705:63;135852:57;;;22:32:-1;6:49;;135852:57:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;135816:94:0;;;;135781:12;;135795:17;;-1:-1:-1;;;;;135816:25:0;;;135846:4;;135852:57;;135816:94;;;;25:18:-1;135816: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;;;135816: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;;135780:130:0;;;;135926:7;135921:58;;-1:-1:-1;;135950:17:0;;;;;;135921:58;135991:13;;136023:414;136048:4;:11;136040:1;136044;136040:5;:19;136023:414;;;136085:4;136090:1;136094;136090:5;136085:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136085:11:0;-1:-1:-1;;;136085:18:0;:57;;;;;136124:4;136129:1;136133;136129:5;136124:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136124:11:0;-1:-1:-1;;;136124:18:0;136085:57;:96;;;;;136163:4;136168:1;136172;136168:5;136163:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136163:11:0;-1:-1:-1;;;136163:18:0;136085:96;:135;;;;;136202:4;136207:1;136211;136207:5;136202:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136202:11:0;-1:-1:-1;;;136202:18:0;136085:135;:174;;;;;136241:4;136246:1;136250;136246:5;136241:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136241:11:0;-1:-1:-1;;;136241:18:0;136085:174;:213;;;;;136280:4;136285:1;136289;136285:5;136280:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136280:11:0;-1:-1:-1;;;136280:18:0;136085:213;:252;;;;;136319:4;136324:1;136328;136324:5;136319:11;;;;;;;;;;;;;-1:-1:-1;;;;;;136319:11:0;-1:-1:-1;;;136319:18:0;136085:252;136081:345;;;136382:4;136371:15;;136405:5;;136081:345;136061:3;;136023:414;;;;136452:8;136447:59;;-1:-1:-1;;136477:17:0;;;;;;;136447:59;136572:103;;;22:32:-1;6:49;;136572:103:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;136536:140:0;;;;-1:-1:-1;;;;;136536:25:0;;;136566:4;;136572:103;136536:140;;;25:18:-1;136536: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;;;136536: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;136518:158:0;;-1:-1:-1;136518:158:0;-1:-1:-1;136518:158:0;136687:58;;-1:-1:-1;;136716:17:0;;;;;;;136687:58;136775:4;136764:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;136764:26:0;;135625:1173;-1:-1:-1;;;;;135625:1173:0:o;168383:329::-;168568:136;168592:9;168616;168640:6;168661:12;168688:5;168720:1685;168925:9;-1:-1:-1;;;;;168912:22:0;:9;-1:-1:-1;;;;;168912:22:0;;168908:61;;;168951:7;;168908:61;169031:30;:5;4758:4;169031:30;:11;:30;:::i;:::-;168985:76;;:42;:5;6584:10;168985:42;:11;:42;:::i;:::-;:76;;;168981:1259;;;169078:17;169098:34;169122:9;169098:23;:34::i;:::-;169078:54;-1:-1:-1;;;;;;169151:24:0;;;;169147:323;;169215:9;-1:-1:-1;;;;;169196:37:0;;169234:6;169196:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;169196:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169196:45:0;;;;169269:185;169301:10;169334:9;169366:6;169395:12;169430:5;169269:9;:185::i;:::-;169262:192;;;169147:323;169499:34;169523:9;169499:23;:34::i;:::-;169486:47;-1:-1:-1;;;;;;169552:24:0;;;;169548:681;;169597:187;169631:9;169663:10;169696:6;169725:12;169760:5;169597:11;:187::i;:::-;169805:24;169832:44;-1:-1:-1;;;;;169832:29:0;;169870:4;169832:44;:29;:44;:::i;:::-;169805:71;;169897:58;49064:42;-1:-1:-1;;;;;169925:9:0;;:11;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;169925:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169925:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169925:11:0;-1:-1:-1;;;;;169897:27:0;;;169938:16;169897:58;:27;:58;:::i;:::-;49064:42;169974:12;169993:18;-1:-1:-1;;;;;169993:16:0;;;:18::i;:::-;:41;;170033:1;169993:41;;;170014:16;169993:41;170058:18;:10;-1:-1:-1;;;;;170058:16:0;;:18::i;:::-;:45;;170093:10;170058:45;;;45564:42;170058:45;169974:214;;;-1:-1:-1;;;;;;169974:214:0;;;;;;;-1:-1:-1;;;;;169974:214:0;;;;;;;;;;;;;170165:4;169974:214;;;;;;;;;;-1:-1:-1;;169974:214:0;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;169974:214:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169974:214:0;;;;;170207:7;;;;169548:681;168981:1259;;170259:138;170285:9;170309;170333:6;170354:12;170381:5;170259:11;:138::i;162773:2905::-;162842:6;-1:-1:-1;;;;;162865:59:0;;162881:42;162865:59;162861:115;;;-1:-1:-1;162962:1:0;162948:16;;162861:115;-1:-1:-1;;;;;162990:59:0;;163006:42;162990:59;162986:156;;;-1:-1:-1;;;;;;;;;;;;163073:57:0;;162986:156;-1:-1:-1;;;;;163156:59:0;;163172:42;163156:59;163152:157;;;-1:-1:-1;163254:42:0;163240:57;;163152:157;-1:-1:-1;;;;;163323:59:0;;163339:42;163323:59;163319:157;;;-1:-1:-1;163421:42:0;163407:57;;163319:157;-1:-1:-1;;;;;163490:59:0;;163506:42;163490:59;163486:157;;;-1:-1:-1;163588:42:0;163574:57;;163486:157;-1:-1:-1;;;;;163657:59:0;;163673:42;163657:59;163653:157;;;-1:-1:-1;163755:42:0;163741:57;;163653:157;-1:-1:-1;;;;;163824:59:0;;163840:42;163824:59;163820:157;;;-1:-1:-1;163922:42:0;163908:57;;163820:157;-1:-1:-1;;;;;163991:59:0;;164007:42;163991:59;163987:156;;;-1:-1:-1;164088:42:0;164074:57;;163987:156;-1:-1:-1;;;;;164157:59:0;;164173:42;164157:59;164153:156;;;-1:-1:-1;164254:42:0;164240:57;;164153:156;-1:-1:-1;;;;;164323:59:0;;164339:42;164323:59;164319:157;;;-1:-1:-1;164421:42:0;164407:57;;164319:157;-1:-1:-1;;;;;164490:59:0;;164506:42;164490:59;164486:157;;;-1:-1:-1;164588:42:0;164574:57;;164486:157;-1:-1:-1;;;;;164657:59:0;;164673:42;164657:59;164653:157;;;-1:-1:-1;164755:42:0;164741:57;;164653:157;-1:-1:-1;;;;;164824:59:0;;164840:42;164824:59;164820:156;;;-1:-1:-1;164921:42:0;164907:57;;164820:156;-1:-1:-1;;;;;164990:59:0;;165006:42;164990:59;164986:156;;;-1:-1:-1;165087:42:0;165073:57;;164986:156;-1:-1:-1;;;;;165156:59:0;;165172:42;165156:59;165152:156;;;-1:-1:-1;165253:42:0;165239:57;;165152:156;-1:-1:-1;;;;;165322:59:0;;165338:42;165322:59;165318:157;;;-1:-1:-1;165420:42:0;165406:57;;165318:157;-1:-1:-1;;;;;165489:59:0;;165505:42;165489:59;165485:156;;;-1:-1:-1;165586:42:0;165572:57;;147990:1707;148192:9;-1:-1:-1;;;;;148179:22:0;:9;-1:-1:-1;;;;;148179:22:0;;148175:61;;;148218:7;;148175:61;148298:30;:5;4972;148298:30;:11;:30;:::i;:::-;148252:76;;:42;:5;6584:10;148252:42;:11;:42;:::i;:::-;:76;;;148248:1360;;;-1:-1:-1;;;;;148349:25:0;;145941:42;148349:25;148345:913;;;145941:42;-1:-1:-1;;;;;148395:9:0;;148405:6;148395:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;148395:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;148454:28:0;;;-1:-1:-1;;;148454:28:0;;148476:4;148454:28;;;;;;148433:18;;-1:-1:-1;146029:42:0;;-1:-1:-1;148454:13:0;;:28;;;;;;;;;;;;;;;146029:42;148454:28;;;5:2:-1;;;;30:1;27;20:12;5:2;148454:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;148454:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;148454:28:0;;-1:-1:-1;148505:14:0;;148501:534;;148546:32;148582:203;146029:42;148656:9;148692:10;148729:1;148757:5;148582:17;:203::i;:::-;148544:241;;;148810:205;146029:42;148872:9;148908:10;148945:15;148987:5;148810;:205::i;:::-;148501:534;;149062:180;-1:-1:-1;;;;;;;;;;;149122:9:0;149154:6;149183:12;149218:5;149062:11;:180::i;148345:913::-;-1:-1:-1;;;;;149278:25:0;;145941:42;149278:25;149274:323;;;149324:56;149336:9;-1:-1:-1;;;;;;;;;;;149352:6:0;149360:12;149374:5;149324:11;:56::i;:::-;149422:28;;;-1:-1:-1;;;149422:28:0;;149444:4;149422:28;;;;;;149401:18;;-1:-1:-1;;;;;;;;;;;45951:42:0;149422:13;;:28;;;;;;;;;;;;;;;45951:42;149422:28;;;5:2:-1;;;;30:1;27;20:12;5:2;149422:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149422:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;149422:28:0;;-1:-1:-1;149469:47:0;-1:-1:-1;;;;;;;;;;;145941:42:0;149422:28;149469:47;:20;:47;:::i;:::-;145941:42;-1:-1:-1;;;;;149535:9:0;;149545:10;149535:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;149274:323:0;149627:62;149639:9;149650;149661:6;149669:12;149683:5;144271:1337;144473:9;-1:-1:-1;;;;;144460:22:0;:9;-1:-1:-1;;;;;144460:22:0;;144456:61;;;144499:7;;144456:61;144579:30;:5;4701:4;144579:30;:11;:30;:::i;:::-;144533:76;;:42;:5;6584:10;144533:42;:11;:42;:::i;:::-;:76;;;144529:914;;;-1:-1:-1;;;;;144630:25:0;;45863:42;144630:25;144626:328;;;144676:32;;;-1:-1:-1;;;144676:32:0;;144694:4;144676:32;;;;;;;;;;;;45863:42;;144676:9;;:32;;;;;-1:-1:-1;;144676:32:0;;;;;;;-1:-1:-1;45863:42:0;144676:32;;;5:2:-1;;;;30:1;27;20:12;5:2;144676:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;144828:28:0;;;-1:-1:-1;;;144828:28:0;;144850:4;144828:28;;;;;;144736:202;;-1:-1:-1;;;;;;;;;;;;45951:42:0;-1:-1:-1;144796:9:0;;45951:42;;144828:13;;:28;;;;;;;;;;;;;;;45951:42;144828:28;;;5:2:-1;;;;30:1;27;20:12;5:2;144828:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144828:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144828:28:0;144879:12;144914:5;144736:11;:202::i;144626:328::-;-1:-1:-1;;;;;144974:25:0;;45863:42;144974:25;144970:462;;;145020:180;145054:9;-1:-1:-1;;;;;;;;;;;145112:6:0;145141:12;145176:5;145020:11;:180::i;:::-;145242:28;;;-1:-1:-1;;;145242:28:0;;145264:4;145242:28;;;;;;145221:18;;-1:-1:-1;;;;;;;;;;;45951:42:0;145242:13;;:28;;;;;;;;;;;;;;;45951:42;145242:28;;;5:2:-1;;;;30:1;27;20:12;5:2;145242:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;145242:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;145242:28:0;;-1:-1:-1;145289:47:0;-1:-1:-1;;;;;;;;;;;45863:42:0;145242:28;145289:47;:20;:47;:::i;:::-;145355:36;;;-1:-1:-1;;;145355:36:0;;145373:4;145355:36;;;;;;;;;;;;45863:42;;145355:9;;:36;;;;;-1:-1:-1;;145355:36:0;;;;;;;-1:-1:-1;45863:42:0;145355:36;;;5:2:-1;;;;30:1;27;20:12;144970:462:0;145462:138;145488:9;145512;145536:6;145557:12;145584:5;177960:2443;178162:9;-1:-1:-1;;;;;178149:22:0;:9;-1:-1:-1;;;;;178149:22:0;;178145:61;;;178188:7;;178145:61;178268:38;:5;7472:13;178268:38;:11;:38;:::i;:::-;178222:84;;:42;:5;6584:10;178222:42;:11;:42;:::i;:::-;:84;;;178218:2020;;;-1:-1:-1;;;;;178327:25:0;;49708:42;178327:25;178323:935;;;-1:-1:-1;;;;;178377:17:0;;46128:42;178377:17;;:37;;-1:-1:-1;;;;;;178398:16:0;;-1:-1:-1;;;;;;;;;;;178398:16:0;178377:37;:58;;;-1:-1:-1;;;;;;178418:17:0;;46217:42;178418:17;178377:58;:79;;;-1:-1:-1;;;;;;178439:17:0;;46306:42;178439:17;178377:79;178373:845;;;178503:59;;;-1:-1:-1;;;178503:59:0;;-1:-1:-1;;;;;178503:59:0;;;;;;;;;;;;;;;;;;;;;178485:14;;49844:42;;178503:29;;:59;;;;;178485:14;;178503:59;;;;;;;;49844:42;178503:59;;;5:2:-1;;;;30:1;27;20:12;5:2;178503:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;178503:59:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;178503: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;178503: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;178503:59:0;;420:4:-1;411:14;;;;178503:59:0;;;;;411:14:-1;178503: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;178503:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;178503:59:0;;;;;;;;;-1:-1:-1;;;178585:103:0;;-1:-1:-1;;;;;178585:103:0;;;;;;;;;;;;;;178503:59;;-1:-1:-1;49708:42:0;;-1:-1:-1;178585:11:0;;-1:-1:-1;178585:103:0;;;;;-1:-1:-1;178503:59:0;;-1:-1:-1;178585:103:0;;;;;;;-1:-1:-1;49708:42:0;178585:103;;;5:2:-1;;;;30:1;27;20:12;5:2;178585:103:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;178585:103:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;178373:845:0;;-1:-1:-1;;178373:845:0;;178776:53;;;-1:-1:-1;;;178776:53:0;;-1:-1:-1;;;;;178776:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;178776:53:0;;;;;;178758:14;;49844:42;;178776:29;;:53;;;;;178758:14;;178776:53;;;;;;;;49844:42;178776:53;;;5:2:-1;;;;30:1;27;20:12;5:2;178776:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;178776:53:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;178776: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;178776: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;178776:53:0;;420:4:-1;411:14;;;;178776:53:0;;;;;411:14:-1;178776: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;178776:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;178776:53:0;;;;;;;;;-1:-1:-1;;;178852:97:0;;-1:-1:-1;;;;;;;;;;;178852:97:0;;;;;;;;;;;;178776:53;;-1:-1:-1;49708:42:0;;-1:-1:-1;178852:11:0;;-1:-1:-1;178852:97:0;;;;;-1:-1:-1;178776:53:0;;-1:-1:-1;178852:97:0;;;;;;;-1:-1:-1;49708:42:0;178852:97;;;5:2:-1;;;;30:1;27;20:12;5:2;178852:97:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;178852:97:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;179076:28:0;;;-1:-1:-1;;;179076:28:0;;179098:4;179076:28;;;;;;178972:226;;-1:-1:-1;;;;;;;;;;;45951:42:0;179040:9;;45951:42;;179076:13;;:28;;;;;178852:97;;179076:28;;;;;;;;45951:42;179076:28;;;5:2:-1;;;;30:1;27;20:12;5:2;179076:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179076:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179076:28:0;179131:12;179170:5;178972:11;:226::i;178323:935::-;-1:-1:-1;;;;;179278:25:0;;49708:42;179278:25;179274:953;;;-1:-1:-1;;;;;179328:17:0;;46128:42;179328:17;;:37;;-1:-1:-1;;;;;;179349:16:0;;-1:-1:-1;;;;;;;;;;;179349:16:0;179328:37;:58;;;-1:-1:-1;;;;;;179369:17:0;;46217:42;179369:17;179328:58;:79;;;-1:-1:-1;;;;;;179390:17:0;;46306:42;179390:17;179328:79;179324:863;;;179432:49;-1:-1:-1;;;;;179432:26:0;;49708:42;179474:6;179432:49;:26;:49;:::i;:::-;179504:177;;;-1:-1:-1;;;179504:177:0;;-1:-1:-1;;;;;179504:177:0;;;;;;;;;;;;;;;;;;;179653:4;179504:177;;;;;;49708:42;;179504:9;;:177;;;;;;;;;;;;;;-1:-1:-1;49708:42:0;179504:177;;;5:2:-1;;;;30:1;27;20:12;5:2;179504:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179504:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179324:863:0;;-1:-1:-1;179324:863:0;;179747:204;179785:9;-1:-1:-1;;;;;;;;;;;179851:6:0;179884:12;179923:5;179747:11;:204::i;:::-;180076:28;;;-1:-1:-1;;;180076:28:0;;180098:4;180076:28;;;;;;49708:42;;179974:9;;-1:-1:-1;;;;;;;;;;;45951:42:0;180040:9;;45951:42;;180076:13;;:28;;;;;;;;;;;;;;45951:42;180076:28;;;5:2:-1;;;;30:1;27;20:12;5:2;180076:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;180076:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180076:28:0;179974:193;;;-1:-1:-1;;;;;;179974:193:0;;;;;;;-1:-1:-1;;;;;179974:193:0;;;;;;;;;;;;;;;;;;;180139:4;179974:193;;;;;;;;;;;180076:28;;179974:193;;;;;;;-1:-1:-1;179974:193:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;179974:193:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179974:193:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;179274:953:0;180257:138;180283:9;180307;180331:6;180352:12;180379:5;101369:437;101605:9;-1:-1:-1;;;;;101592:22:0;:9;-1:-1:-1;;;;;101592:22:0;;101588:61;;;101631:7;;101588:61;101661:137;101686:9;101710;101734:6;101755:12;101782:5;195556:8;;195521:53;;-1:-1:-1;;;;;195521:26:0;;;;195556:8;195567:6;195521:53;:26;:53;:::i;:::-;195585:8;;-1:-1:-1;;;;;195585:8:0;;;;:13;;195605:17;;:15;;;:17::i;:::-;:30;;195634:1;195605:30;;;195625:6;195605:30;195651:9;195675;195699:6;195720:1;195736:12;195763:5;195585:194;;;;;;;;;;;;;-1:-1:-1;;;;;195585:194:0;-1:-1:-1;;;;;195585:194:0;;;;;;-1:-1:-1;;;;;195585:194:0;-1:-1:-1;;;;;195585:194: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;195585:194:0;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;195585:194:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;195585:194:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;195331:456:0:o;189948:5842::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;189948:5842:0;;;-1:-1:-1;;189948:5842:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;189948:5842:0;;;-1:-1:-1;;189948:5842:0:o
Swarm Source
bzzr://293752088a2aec2583d287e39911b8b86603464ae8a1e18961dd33188fb98766
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.