Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
10849650 | 1532 days ago | 7.6069429 ETH | ||||
10849650 | 1532 days ago | 7.6069429 ETH | ||||
10813370 | 1538 days ago | 200 ETH | ||||
10813370 | 1538 days ago | 200 ETH | ||||
10765794 | 1545 days ago | 1.76520306 ETH | ||||
10765794 | 1545 days ago | 1.76520306 ETH | ||||
10708668 | 1554 days ago | 25.43990337 ETH | ||||
10708668 | 1554 days ago | 25.43990337 ETH | ||||
10698036 | 1555 days ago | 0.89 ETH | ||||
10698036 | 1555 days ago | 0.89 ETH | ||||
10682789 | 1558 days ago | 1.03031249 ETH | ||||
10682789 | 1558 days ago | 1.03031249 ETH | ||||
10662675 | 1561 days ago | 0.50229869 ETH | ||||
10662675 | 1561 days ago | 0.50229869 ETH | ||||
10660223 | 1561 days ago | 27.5 ETH | ||||
10660223 | 1561 days ago | 27.5 ETH | ||||
10648775 | 1563 days ago | 0.53566948 ETH | ||||
10648775 | 1563 days ago | 0.53566948 ETH | ||||
10648461 | 1563 days ago | 4 ETH | ||||
10648461 | 1563 days ago | 4 ETH | ||||
10638643 | 1564 days ago | 3 ETH | ||||
10638643 | 1564 days ago | 3 ETH | ||||
10638419 | 1564 days ago | 16.26823964 ETH | ||||
10638419 | 1564 days ago | 16.26823964 ETH | ||||
10638419 | 1564 days ago | 66.60053424 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-08-06 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/IOneSplit.sol pragma solidity ^0.5.0; // // [ msg.sender ] // | | // | | // \_/ // +---------------+ ________________________________ // | OneSplitAudit | _______________________________ \ // +---------------+ \ \ // | | ______________ | | (staticcall) // | | / ____________ \ | | // | | (call) / / \ \ | | // | | / / | | | | // \_/ | | \_/ \_/ // +--------------+ | | +----------------------+ // | OneSplitWrap | | | | OneSplitViewWrap | // +--------------+ | | +----------------------+ // | | | | | | // | | (delegatecall) | | (staticcall) | | (staticcall) // \_/ | | \_/ // +--------------+ | | +------------------+ // | OneSplit | | | | OneSplitView | // +--------------+ | | +------------------+ // | | / / // \ \________________/ / // \__________________/ // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01; uint256 internal constant DEPRECATED_FLAG_DISABLE_KYBER = 0x02; // Deprecated uint256 internal constant FLAG_DISABLE_BANCOR = 0x04; uint256 internal constant FLAG_DISABLE_OASIS = 0x08; uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10; uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20; uint256 internal constant FLAG_DISABLE_CHAI = 0x40; uint256 internal constant FLAG_DISABLE_AAVE = 0x80; uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_BDAI = 0x400; uint256 internal constant FLAG_DISABLE_IEARN = 0x800; uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 internal constant FLAG_DISABLE_WETH = 0x80000; uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_IDLE = 0x800000; uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000; uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000; uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000; uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000; uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000; uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000; uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_KYBER_ALL = 0x200000000000000; uint256 internal constant FLAG_DISABLE_KYBER_1 = 0x400000000000000; uint256 internal constant FLAG_DISABLE_KYBER_2 = 0x800000000000000; uint256 internal constant FLAG_DISABLE_KYBER_3 = 0x1000000000000000; uint256 internal constant FLAG_DISABLE_KYBER_4 = 0x2000000000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN_BY_ORIGIN = 0x4000000000000000; uint256 internal constant FLAG_DISABLE_MOONISWAP_ALL = 0x8000000000000000; uint256 internal constant FLAG_DISABLE_MOONISWAP_ETH = 0x10000000000000000; uint256 internal constant FLAG_DISABLE_MOONISWAP_DAI = 0x20000000000000000; uint256 internal constant FLAG_DISABLE_MOONISWAP_USDC = 0x40000000000000000; uint256 internal constant FLAG_DISABLE_MOONISWAP_POOL_TOKEN = 0x80000000000000000; } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount); } contract IOneSplitMulti is IOneSplit { function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ); function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/interface/IUniswapExchange.sol pragma solidity ^0.5.0; interface IUniswapExchange { function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought); function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought); function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256 tokensBought); function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); } // File: contracts/interface/IKyberNetworkContract.sol pragma solidity ^0.5.0; interface IKyberNetworkContract { function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless) external view returns (address reserve, uint256 rate); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity ^0.5.0; interface IKyberNetworkProxy { function getExpectedRateAfterFee( IERC20 src, IERC20 dest, uint256 srcQty, uint256 platformFeeBps, bytes calldata hint ) external view returns (uint256 expectedRate); function tradeWithHintAndFee( IERC20 src, uint256 srcAmount, IERC20 dest, address payable destAddress, uint256 maxDestAmount, uint256 minConversionRate, address payable platformWallet, uint256 platformFeeBps, bytes calldata hint ) external payable returns (uint256 destAmount); function kyberNetworkContract() external view returns (IKyberNetworkContract); // TODO: Limit usage by tx.gasPrice // function maxGasPrice() external view returns (uint256); // TODO: Limit usage by user cap // function getUserCapInWei(address user) external view returns (uint256); // function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256); } // File: contracts/interface/IKyberStorage.sol pragma solidity ^0.5.0; interface IKyberStorage { function getReserveIdsPerTokenSrc( IERC20 token ) external view returns (bytes32[] memory); } // File: contracts/interface/IKyberHintHandler.sol pragma solidity ^0.5.0; interface IKyberHintHandler { enum TradeType { BestOfAll, MaskIn, MaskOut, Split } function buildTokenToEthHint( IERC20 tokenSrc, TradeType tokenToEthType, bytes32[] calldata tokenToEthReserveIds, uint256[] calldata tokenToEthSplits ) external view returns (bytes memory hint); function buildEthToTokenHint( IERC20 tokenDest, TradeType ethToTokenType, bytes32[] calldata ethToTokenReserveIds, uint256[] calldata ethToTokenSplits ) external view returns (bytes memory hint); } // File: contracts/interface/IBancorNetwork.sol pragma solidity ^0.5.0; interface IBancorNetwork { function getReturnByPath(address[] calldata path, uint256 amount) external view returns (uint256 returnAmount, uint256 conversionFee); function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn) external returns (uint256); function convert(address[] calldata path, uint256 amount, uint256 minReturn) external payable returns (uint256); } // File: contracts/interface/IBancorContractRegistry.sol pragma solidity ^0.5.0; contract IBancorContractRegistry { function addressOf(bytes32 contractName) external view returns (address); } // File: contracts/interface/IBancorNetworkPathFinder.sol pragma solidity ^0.5.0; interface IBancorNetworkPathFinder { function generatePath(IERC20 sourceToken, IERC20 targetToken) external view returns (address[] memory); } // File: contracts/interface/IBancorConverterRegistry.sol pragma solidity ^0.5.0; interface IBancorConverterRegistry { function getConvertibleTokenSmartTokenCount(IERC20 convertibleToken) external view returns(uint256); function getConvertibleTokenSmartTokens(IERC20 convertibleToken) external view returns(address[] memory); function getConvertibleTokenSmartToken(IERC20 convertibleToken, uint256 index) external view returns(address); function isConvertibleTokenSmartToken(IERC20 convertibleToken, address value) external view returns(bool); } // File: contracts/interface/IBancorEtherToken.sol pragma solidity ^0.5.0; contract IBancorEtherToken is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/IBancorFinder.sol pragma solidity ^0.5.0; interface IBancorFinder { function buildBancorPath( IERC20 fromToken, IERC20 destToken ) external view returns(address[] memory path); } // File: contracts/interface/IOasisExchange.sol pragma solidity ^0.5.0; interface IOasisExchange { function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt) external view returns (uint256 fillAmt); function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount) external returns (uint256 fillAmt); } // File: contracts/interface/IWETH.sol pragma solidity ^0.5.0; contract IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/ICurve.sol pragma solidity ^0.5.0; interface ICurve { // solium-disable-next-line mixedcase function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external; // solium-disable-next-line mixedcase function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external; } contract ICurveRegistry { function get_pool_info(address pool) external view returns( uint256[8] memory balances, uint256[8] memory underlying_balances, uint256[8] memory decimals, uint256[8] memory underlying_decimals, address lp_token, uint256 A, uint256 fee ); } contract ICurveCalculator { function get_dy( int128 nCoins, uint256[8] calldata balances, uint256 amp, uint256 fee, uint256[8] calldata rates, uint256[8] calldata precisions, bool underlying, int128 i, int128 j, uint256[100] calldata dx ) external view returns(uint256[100] memory dy); } // File: contracts/interface/IChai.sol pragma solidity ^0.5.0; interface IPot { function dsr() external view returns (uint256); function chi() external view returns (uint256); function rho() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } contract IChai is IERC20 { function POT() public view returns (IPot); function join(address dst, uint256 wad) external; function exit(address src, uint256 wad) external; } library ChaiHelper { IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7); uint256 private constant RAY = 10**27; function _mul(uint256 x, uint256 y) private pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, y) / RAY; } function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, RAY) / y; } function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) { // solium-disable-next-line security/no-inline-assembly assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } function potDrip() private view returns (uint256) { return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi()); } function chaiPrice(IChai chai) internal view returns(uint256) { return chaiToDai(chai, 1e18); } function daiToChai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rdiv(amount, chi); } function chaiToDai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rmul(chi, amount); } } // File: contracts/interface/ICompound.sol pragma solidity ^0.5.0; contract ICompound { function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa); } contract ICompoundToken is IERC20 { function underlying() external view returns (address); function exchangeRateStored() external view returns (uint256); function mint(uint256 mintAmount) external returns (uint256); function redeem(uint256 redeemTokens) external returns (uint256); } contract ICompoundEther is IERC20 { function mint() external payable; function redeem(uint256 redeemTokens) external returns (uint256); } // File: contracts/interface/ICompoundRegistry.sol pragma solidity ^0.5.0; contract ICompoundRegistry { function tokenByCToken(ICompoundToken cToken) external view returns(IERC20); function cTokenByToken(IERC20 token) external view returns(ICompoundToken); } // File: contracts/interface/IAaveToken.sol pragma solidity ^0.5.0; contract IAaveToken is IERC20 { function underlyingAssetAddress() external view returns (IERC20); function redeem(uint256 amount) external; } interface IAaveLendingPool { function core() external view returns (address); function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable; } // File: contracts/interface/IAaveRegistry.sol pragma solidity ^0.5.0; contract IAaveRegistry { function tokenByAToken(IAaveToken aToken) external view returns(IERC20); function aTokenByToken(IERC20 token) external view returns(IAaveToken); } // File: contracts/interface/IMooniswap.sol pragma solidity ^0.5.0; interface IMooniswapRegistry { function pools(IERC20 token1, IERC20 token2) external view returns(IMooniswap); function isPool(address addr) external view returns(bool); } interface IMooniswap { function fee() external view returns (uint256); function tokens(uint256 i) external view returns (IERC20); function deposit(uint256[] calldata amounts, uint256 minReturn) external payable returns(uint256 fairSupply); function withdraw(uint256 amount, uint256[] calldata minReturns) external; function getBalanceForAddition(IERC20 token) external view returns(uint256); function getBalanceForRemoval(IERC20 token) external view returns(uint256); function getReturn( IERC20 fromToken, IERC20 destToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, address referral ) 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 eq(IERC20 a, IERC20 b) internal pure returns(bool) { return a == b || (isETH(a) && isETH(b)); } 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 IMassetValidationHelper { /** * @dev Returns a valid bAsset to redeem * @param _mAsset Masset addr * @return valid bool * @return string message * @return address of bAsset to redeem */ function suggestRedeemAsset( IERC20 _mAsset ) external view returns ( bool valid, string memory err, address token ); /** * @dev Returns a valid bAsset with which to mint * @param _mAsset Masset addr * @return valid bool * @return string message * @return address of bAsset to mint */ function suggestMintAsset( IERC20 _mAsset ) external view returns ( bool valid, string memory err, address token ); /** * @dev Determines if a given Redemption is valid * @param _mAsset Address of the given mAsset (e.g. mUSD) * @param _mAssetQuantity Amount of mAsset to redeem (in mUSD units) * @param _outputBasset Desired output bAsset * @return valid * @return validity reason * @return output in bAsset units * @return bAssetQuantityArg - required input argument to the 'redeem' call */ function getRedeemValidity( IERC20 _mAsset, uint256 _mAssetQuantity, IERC20 _outputBasset ) external view returns ( bool valid, string memory, uint256 output, uint256 bassetQuantityArg ); } // File: contracts/interface/IBalancerPool.sol pragma solidity ^0.5.0; interface IBalancerPool { function getSwapFee() external view returns (uint256 balance); function getDenormalizedWeight(IERC20 token) external view returns (uint256 balance); function getBalance(IERC20 token) external view returns (uint256 balance); function swapExactAmountIn( IERC20 tokenIn, uint256 tokenAmountIn, IERC20 tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter); } // 0xA961672E8Db773be387e775bc4937C678F3ddF9a interface IBalancerHelper { function getReturns( IBalancerPool pool, IERC20 fromToken, IERC20 destToken, uint256[] calldata amounts ) external view returns(uint256[] memory rets); } // File: contracts/interface/IBalancerRegistry.sol 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/BalancerLib.sol pragma solidity ^0.5.0; library BalancerLib { uint public constant BONE = 10**18; uint public constant MIN_BOUND_TOKENS = 2; uint public constant MAX_BOUND_TOKENS = 8; uint public constant MIN_FEE = BONE / 10**6; uint public constant MAX_FEE = BONE / 10; uint public constant EXIT_FEE = 0; uint public constant MIN_WEIGHT = BONE; uint public constant MAX_WEIGHT = BONE * 50; uint public constant MAX_TOTAL_WEIGHT = BONE * 50; uint public constant MIN_BALANCE = BONE / 10**12; uint public constant INIT_POOL_SUPPLY = BONE * 100; uint public constant MIN_BPOW_BASE = 1 wei; uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei; uint public constant BPOW_PRECISION = BONE / 10**10; uint public constant MAX_IN_RATIO = BONE / 2; uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; function btoi(uint a) internal pure returns (uint) { return a / BONE; } function bfloor(uint a) internal pure returns (uint) { return btoi(a) * BONE; } function badd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } function bsub(uint a, uint b) internal pure returns (uint) { (uint c, bool flag) = bsubSign(a, b); require(!flag, "ERR_SUB_UNDERFLOW"); return c; } function bsubSign(uint a, uint b) internal pure returns (uint, bool) { if (a >= b) { return (a - b, false); } else { return (b - a, true); } } function bmul(uint a, uint b) internal pure returns (uint) { uint c0 = a * b; require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW"); uint c1 = c0 + (BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint c2 = c1 / BONE; return c2; } function bdiv(uint a, uint b) internal pure returns (uint) { require(b != 0, "ERR_DIV_ZERO"); uint c0 = a * BONE; require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint c1 = c0 + (b / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint c2 = c1 / b; return c2; } // DSMath.wpow function bpowi(uint a, uint n) internal pure returns (uint) { uint z = n % 2 != 0 ? a : BONE; for (n /= 2; n != 0; n /= 2) { a = bmul(a, a); if (n % 2 != 0) { z = bmul(z, a); } } return z; } // Compute b^(e.w) by splitting it into (b^e)*(b^0.w). // Use `bpowi` for `b^e` and `bpowK` for k iterations // of approximation of b^0.w function bpow(uint base, uint exp) internal pure returns (uint) { require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW"); require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH"); uint whole = bfloor(exp); uint remain = bsub(exp, whole); uint wholePow = bpowi(base, btoi(whole)); if (remain == 0) { return wholePow; } uint partialResult = bpowApprox(base, remain, BPOW_PRECISION); return bmul(wholePow, partialResult); } function bpowApprox(uint base, uint exp, uint precision) internal pure returns (uint) { // term 0: uint a = exp; (uint x, bool xneg) = bsubSign(base, BONE); uint term = BONE; uint sum = term; bool negative = false; // term(k) = numer / denom // = (product(a - i - 1, i=1-->k) * x^k) / (k!) // each iteration, multiply previous term by (a-(k-1)) * x / k // continue until term is less than precision for (uint i = 1; term >= precision; i++) { uint bigK = i * BONE; (uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE)); term = bmul(term, bmul(c, x)); term = bdiv(term, bigK); if (term == 0) break; if (xneg) negative = !negative; if (cneg) negative = !negative; if (negative) { sum = bsub(sum, term); } else { sum = badd(sum, term); } } return sum; } /********************************************************************************************** // calcSpotPrice // // sP = spotPrice // // bI = tokenBalanceIn ( bI / wI ) 1 // // bO = tokenBalanceOut sP = ----------- * ---------- // // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcSpotPrice( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint swapFee ) internal pure returns (uint spotPrice) { uint numer = bdiv(tokenBalanceIn, tokenWeightIn); uint denom = bdiv(tokenBalanceOut, tokenWeightOut); uint ratio = bdiv(numer, denom); uint scale = bdiv(BONE, bsub(BONE, swapFee)); return (spotPrice = bmul(ratio, scale)); } /********************************************************************************************** // calcOutGivenIn // // aO = tokenAmountOut // // bO = tokenBalanceOut // // bI = tokenBalanceIn / / bI \ (wI / wO) \ // // aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | // // wI = tokenWeightIn \ \ ( bI + ( aI * ( 1 - sF )) / / // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcOutGivenIn( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountIn, uint swapFee ) internal pure returns (uint tokenAmountOut) { uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut); uint adjustedIn = bsub(BONE, swapFee); adjustedIn = bmul(tokenAmountIn, adjustedIn); uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn)); if (y == 0) { return 0; } uint foo = bpow(y, weightRatio); uint bar = bsub(BONE, foo); tokenAmountOut = bmul(tokenBalanceOut, bar); return tokenAmountOut; } /********************************************************************************************** // calcInGivenOut // // aI = tokenAmountIn // // bO = tokenBalanceOut / / bO \ (wO / wI) \ // // bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | // // aO = tokenAmountOut aI = \ \ ( bO - aO ) / / // // wI = tokenWeightIn -------------------------------------------- // // wO = tokenWeightOut ( 1 - sF ) // // sF = swapFee // **********************************************************************************************/ function calcInGivenOut( uint tokenBalanceIn, uint tokenWeightIn, uint tokenBalanceOut, uint tokenWeightOut, uint tokenAmountOut, uint swapFee ) internal pure returns (uint tokenAmountIn) { uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn); uint diff = bsub(tokenBalanceOut, tokenAmountOut); uint y = bdiv(tokenBalanceOut, diff); if (y == 0) { return 0; } uint foo = bpow(y, weightRatio); foo = bsub(foo, BONE); tokenAmountIn = bsub(BONE, swapFee); tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn); return tokenAmountIn; } /********************************************************************************************** // calcPoolOutGivenSingleIn // // pAo = poolAmountOut / \ // // tAi = tokenAmountIn /// / // wI \ \\ \ wI \ // // wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \ -- \ // // tW = totalWeight pAo=|| \ \ \\ tW / // | ^ tW | * pS - pS // // tBi = tokenBalanceIn \\ ------------------------------------- / / // // pS = poolSupply \\ tBi / / // // sF = swapFee \ / // **********************************************************************************************/ function calcPoolOutGivenSingleIn( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint tokenAmountIn, uint swapFee ) internal pure returns (uint poolAmountOut) { // Charge the trading fee for the proportion of tokenAi /// which is implicitly traded to the other pool tokens. // That proportion is (1- weightTokenIn) // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee); uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz)); uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee); uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn); // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply; uint poolRatio = bpow(tokenInRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); poolAmountOut = bsub(newPoolSupply, poolSupply); return poolAmountOut; } /********************************************************************************************** // calcSingleInGivenPoolOut // // tAi = tokenAmountIn //(pS + pAo)\ / 1 \\ // // pS = poolSupply || --------- | ^ | --------- || * bI - bI // // pAo = poolAmountOut \\ pS / \(wI / tW)// // // bI = balanceIn tAi = -------------------------------------------- // // wI = weightIn / wI \ // // tW = totalWeight | 1 - ---- | * sF // // sF = swapFee \ tW / // **********************************************************************************************/ function calcSingleInGivenPoolOut( uint tokenBalanceIn, uint tokenWeightIn, uint poolSupply, uint totalWeight, uint poolAmountOut, uint swapFee ) internal pure returns (uint tokenAmountIn) { uint normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint newPoolSupply = badd(poolSupply, poolAmountOut); uint poolRatio = bdiv(newPoolSupply, poolSupply); //uint newBalTi = poolRatio^(1/weightTi) * balTi; uint boo = bdiv(BONE, normalizedWeight); uint tokenInRatio = bpow(poolRatio, boo); uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn); uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn); // Do reverse order of fees charged in joinswap_ExternAmountIn, this way // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ``` //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ; uint zar = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar)); return tokenAmountIn; } /********************************************************************************************** // calcSingleOutGivenPoolIn // // tAo = tokenAmountOut / / \\ // // bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \ / 1 \ \\ // // pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || // // ps = poolSupply \ \\ pS / \(wO / tW)/ // // // wI = tokenWeightIn tAo = \ \ // // // tW = totalWeight / / wO \ \ // // sF = swapFee * | 1 - | 1 - ---- | * sF | // // eF = exitFee \ \ tW / / // **********************************************************************************************/ function calcSingleOutGivenPoolIn( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint poolAmountIn, uint swapFee ) internal pure returns (uint tokenAmountOut) { uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); // charge exit fee on the pool token side // pAiAfterExitFee = pAi*(1-exitFee) uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE)); uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee); uint poolRatio = bdiv(newPoolSupply, poolSupply); // newBalTo = poolRatio^(1/weightTo) * balTo; uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight)); uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut); uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut); // charge swap fee on the output token side //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee) uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz)); return tokenAmountOut; } /********************************************************************************************** // calcPoolInGivenSingleOut // // pAi = poolAmountIn // / tAo \\ / wO \ \ // // bO = tokenBalanceOut // | bO - -------------------------- |\ | ---- | \ // // tAo = tokenAmountOut pS - || \ 1 - ((1 - (tO / tW)) * sF)/ | ^ \ tW / * pS | // // ps = poolSupply \\ -----------------------------------/ / // // wO = tokenWeightOut pAi = \\ bO / / // // tW = totalWeight ------------------------------------------------------------- // // sF = swapFee ( 1 - eF ) // // eF = exitFee // **********************************************************************************************/ function calcPoolInGivenSingleOut( uint tokenBalanceOut, uint tokenWeightOut, uint poolSupply, uint totalWeight, uint tokenAmountOut, uint swapFee ) internal pure returns (uint poolAmountIn) { // charge swap fee on the output token side uint normalizedWeight = bdiv(tokenWeightOut, totalWeight); //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ; uint zoo = bsub(BONE, normalizedWeight); uint zar = bmul(zoo, swapFee); uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar)); uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee); uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut); //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply; uint poolRatio = bpow(tokenOutRatio, normalizedWeight); uint newPoolSupply = bmul(poolRatio, poolSupply); uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply); // charge exit fee on the pool token side // pAi = pAiAfterExitFee/(1-exitFee) poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE)); return poolAmountIn; } } // 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 = 34; IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IERC20 constant internal ZERO_ADDRESS = IERC20(0); IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D); IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847); IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380); IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6); IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e); IKyberStorage constant internal kyberStorage = IKyberStorage(0xC8fb12402cB16970F3C5F4b48Ff68Eb9D1289301); IKyberHintHandler constant internal kyberHintHandler = IKyberHintHandler(0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C); IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); //IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); IBancorFinder constant internal bancorFinder = IBancorFinder(0x2B344e14dc2641D11D338C053C908c7A7D4c30B9); IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D); ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); ICurve constant internal curveRenBTC = ICurve(0x93054188d876f558f4a66B2EF1d97d16eDf0895B); ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E); ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714); IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D); IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0xc12A7e093832E2d2267df225BAca60bD2B74C65F); IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2); IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5); IMassetValidationHelper constant internal musd_helper = IMassetValidationHelper(0xaBcC93c3be238884cc3309C19Afd128fAfC16911); IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982); ICurveCalculator constant internal curveCalculator = ICurveCalculator(0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E); ICurveRegistry constant internal curveRegistry = ICurveRegistry(0x7002B727Ef8F5571Cb5F9D70D13DBEEb4dFAe9d1); ICompoundRegistry constant internal compoundRegistry = ICompoundRegistry(0xF451Dbd7Ba14BFa7B1B78A766D3Ed438F79EE1D1); IAaveRegistry constant internal aaveRegistry = IAaveRegistry(0xEd8b133B7B88366E01Bb9E38305Ab11c26521494); IBalancerHelper constant internal balancerHelper = IBalancerHelper(0xA961672E8Db773be387e775bc4937C678F3ddF9a); int256 internal constant VERY_NEGATIVE_VALUE = -1e72; function _findBestDistribution( uint256 s, // parts int256[][] memory amounts // exchangesReturns ) internal pure returns( int256 returnAmount, uint256[] memory distribution ) { uint256 n = amounts.length; int256[][] memory answer = new int256[][](n); // int[n][s+1] uint256[][] memory parent = new uint256[][](n); // int[n][s+1] for (uint i = 0; i < n; i++) { answer[i] = new int256[](s + 1); parent[i] = new uint256[](s + 1); } for (uint j = 0; j <= s; j++) { answer[0][j] = amounts[0][j]; for (uint i = 1; i < n; i++) { answer[i][j] = -1e72; } parent[0][j] = 0; } for (uint i = 1; i < n; i++) { for (uint j = 0; j <= s; j++) { answer[i][j] = answer[i - 1][j]; parent[i][j] = j; for (uint k = 1; k <= j; k++) { if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) { answer[i][j] = answer[i - 1][j - k] + amounts[i][k]; parent[i][j] = j - k; } } } } distribution = new uint256[](DEXES_COUNT); uint256 partsLeft = s; for (uint curExchange = n - 1; partsLeft > 0; curExchange--) { distribution[curExchange] = partsLeft - parent[curExchange][partsLeft]; partsLeft = parent[curExchange][partsLeft]; } returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s]; } function _kyberReserveIdByTokens( IERC20 fromToken, IERC20 destToken ) internal view returns(bytes32) { if (!fromToken.isETH() && !destToken.isETH()) { return 0; } bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc( fromToken.isETH() ? destToken : fromToken ); for (uint i = 0; i < reserveIds.length; i++) { if ((uint256(reserveIds[i]) >> 248) != 0xBB && // Bridge reserveIds[i] != 0xff4b796265722046707200000000000000000000000000000000000000000000 && // Reserve 1 reserveIds[i] != 0xffabcd0000000000000000000000000000000000000000000000000000000000 && // Reserve 2 reserveIds[i] != 0xff4f6e65426974205175616e7400000000000000000000000000000000000000) // Reserve 3 { return reserveIds[i]; } } return 0; } function _scaleDestTokenEthPriceTimesGasPrice( IERC20 fromToken, IERC20 destToken, uint256 destTokenEthPriceTimesGasPrice ) internal view returns(uint256) { if (fromToken == destToken) { return destTokenEthPriceTimesGasPrice; } uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 0.01 ether); uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 0.01 ether); if (div > 0) { return destTokenEthPriceTimesGasPrice.mul(mul).div(div); } return 0; } function _cheapGetPrice( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal view returns(uint256 returnAmount) { (returnAmount,,) = this.getExpectedReturnWithGas( fromToken, destToken, amount, 1, FLAG_DISABLE_SPLIT_RECALCULATION | FLAG_DISABLE_ALL_SPLIT_SOURCES | FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP, 0 ); } function _linearInterpolation( uint256 value, uint256 parts ) internal pure returns(uint256[] memory rets) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) { return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB); } } contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = this.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _getExpectedReturnRespectingGasFloor( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } contract OneSplitView is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); if (fromToken == destToken) { return (amount, 0, distribution); } function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags); int256[][] memory matrix = new int256[][](DEXES_COUNT); uint256[DEXES_COUNT] memory gases; bool atLeastOnePositive = false; for (uint i = 0; i < DEXES_COUNT; i++) { uint256[] memory rets; (rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags); // Prepend zero and sub gas int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18)); matrix[i] = new int256[](parts + 1); for (uint j = 0; j < rets.length; 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", true, // "Mooniswap 1", true, // "Uniswap V2", true, // "Uniswap V2 (ETH)", true, // "Uniswap V2 (DAI)", true, // "Uniswap V2 (USDC)", true, // "Curve Pax", true, // "Curve RenBTC", true, // "Curve tBTC", true, // "Dforce XSwap", false, // "Shell", true, // "mStable", true, // "Curve sBTC" true, // "Balancer 1" true, // "Balancer 2" true, // "Balancer 3" true, // "Kyber 1" true, // "Kyber 2" true, // "Kyber 3" true, // "Kyber 4" true, // "Mooniswap 2" true, // "Mooniswap 3" true // "Mooniswap 4" ]; for (uint i = 0; i < DEXES_COUNT; i++) { if (args.distribution[i] > 0) { if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add(uint256( (value == VERY_NEGATIVE_VALUE ? 0 : value) + int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18)) )); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves(uint256 flags) internal pure returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory) { bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); return [ invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap, _calculateNoReturn, // invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC, invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap, invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell, invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_1) ? _calculateNoReturn : calculateKyber1, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_2) ? _calculateNoReturn : calculateKyber2, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_3) ? _calculateNoReturn : calculateKyber3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_4) ? _calculateNoReturn : calculateKyber4, invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_ETH) ? _calculateNoReturn : calculateMooniswapOverETH, invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_DAI) ? _calculateNoReturn : calculateMooniswapOverDAI, invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_USDC) ? _calculateNoReturn : calculateMooniswapOverUSDC ]; } 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 struct Balances { uint256 src; uint256 dst; } function _calculateBalancer( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 poolIndex ) internal view returns(uint256[] memory rets, uint256 gas) { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (poolIndex >= pools.length) { return (new uint256[](parts), 0); } rets = balancerHelper.getReturns( IBalancerPool(pools[poolIndex]), fromToken.isETH() ? weth : fromToken, destToken.isETH() ? weth : destToken, _linearInterpolation(amount, parts) ); gas = 75_000 + (fromToken.isETH() || destToken.isETH() ? 0 : 65_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, 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, 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, 2 ); } function calculateMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) || (destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd)) { return (rets, 0); } for (uint i = 1; i <= parts; i *= 2) { (bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector( musd.getSwapOutput.selector, fromToken, destToken, amount.mul(parts.div(i)).div(parts) )); if (success && data.length > 0) { (,, uint256 maxRet) = abi.decode(data, (bool,string,uint256)); if (maxRet > 0) { for (uint j = 0; j < parts.div(i); j++) { rets[j] = maxRet.mul(j + 1).div(parts.div(i)); } break; } } } return ( rets, 700_000 ); } function _getCurvePoolInfo( ICurve curve, bool haveUnderlying ) internal view returns( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) { uint256[8] memory underlying_balances; uint256[8] memory decimals; uint256[8] memory underlying_decimals; ( balances, underlying_balances, decimals, underlying_decimals, /*address lp_token*/, amp, fee ) = curveRegistry.get_pool_info(address(curve)); for (uint k = 0; k < 8 && balances[k] > 0; k++) { precisions[k] = 10 ** (18 - (haveUnderlying ? underlying_decimals : decimals)[k]); if (haveUnderlying) { rates[k] = underlying_balances[k].mul(1e18).div(balances[k]); } else { rates[k] = 1e18; } } } function _calculateCurveSelector( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, ICurve curve, bool haveUnderlying, IERC20[] memory tokens ) internal view returns(uint256[] memory rets) { rets = new uint256[](parts); int128 i = 0; int128 j = 0; for (uint t = 0; t < tokens.length; t++) { if (fromToken == tokens[t]) { i = int128(t + 1); } if (destToken == tokens[t]) { j = int128(t + 1); } } if (i == 0 || j == 0) { return rets; } bytes memory data = abi.encodePacked( uint256(haveUnderlying ? 1 : 0), uint256(i - 1), uint256(j - 1), _linearInterpolation100(amount, parts) ); ( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) = _getCurvePoolInfo(curve, haveUnderlying); bool success; (success, data) = address(curveCalculator).staticcall( abi.encodePacked( abi.encodeWithSelector( curveCalculator.get_dy.selector, tokens.length, balances, amp, fee, rates, precisions ), data ) ); if (!success || data.length == 0) { return rets; } uint256[100] memory dy = abi.decode(data, (uint256[100])); for (uint t = 0; t < parts; t++) { rets[t] = dy[t]; } } function _linearInterpolation100( uint256 value, uint256 parts ) internal pure returns(uint256[100] memory rets) { for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function calculateCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = dai; tokens[1] = usdc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveCompound, true, tokens ), 720_000); } function calculateCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveUSDT, true, tokens ), 720_000); } function calculateCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = tusd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveY, true, tokens ), 1_400_000); } function calculateCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = busd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveBinance, true, tokens ), 1_400_000); } function calculateCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = susd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSynthetix, true, tokens ), 200_000); } function calculateCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = pax; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curvePAX, true, tokens ), 1_000_000); } function calculateCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = renbtc; tokens[1] = wbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveRenBTC, false, tokens ), 130_000); } function calculateCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = tbtc; tokens[1] = wbtc; tokens[2] = hbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveTBTC, false, tokens ), 145_000); } function calculateCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = renbtc; tokens[1] = wbtc; tokens[2] = sbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSBTC, false, tokens ), 150_000); } function calculateShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector( shell.viewOriginTrade.selector, fromToken, destToken, amount )); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 300_000); } function calculateDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(dforceSwap).staticcall( abi.encodeWithSelector( dforceSwap.getAmountByInput.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); uint256 available = destToken.universalBalanceOf(address(dforceSwap)); if (maxRet > available) { return (new uint256[](parts), 0); } return (_linearInterpolation(maxRet, parts), 160_000); } function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) { if (amount == 0) { return 0; } return amount.mul(toBalance).mul(997).div( fromBalance.mul(1000).add(amount.mul(997)) ); } function _calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = amounts; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange)); uint256 fromEtherBalance = address(fromExchange).balance; for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 toEtherBalance = address(toExchange).balance; uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange)); for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]); } } return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000); } function calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswap( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function _calculateUniswapWrapped( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 midTokenPrice, uint256 flags, uint256 gas1, uint256 gas2 ) internal view returns(uint256[] memory rets, uint256 gas) { if (!fromToken.isETH() && destToken.isETH()) { (rets, gas) = _calculateUniswap( midToken, destToken, _linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts), flags ); return (rets, gas + gas1); } else if (fromToken.isETH() && !destToken.isETH()) { (rets, gas) = _calculateUniswap( fromToken, midToken, _linearInterpolation(amount, parts), flags ); for (uint i = 0; i < parts; i++) { rets[i] = rets[i].mul(midTokenPrice).div(1e18); } return (rets, gas + gas2); } return (new uint256[](parts), 0); } function calculateUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { ICompoundToken midToken = compoundRegistry.cTokenByToken(midPreToken); if (midToken != ICompoundToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, midToken.exchangeRateStored(), flags, 200_000, 200_000 ); } } return (new uint256[](parts), 0); } function calculateUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai && destToken.isETH() || fromToken.isETH() && destToken == dai) { return _calculateUniswapWrapped( fromToken, chai, destToken, amount, parts, chai.chaiPrice(), flags, 180_000, 160_000 ); } return (new uint256[](parts), 0); } function calculateUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { IAaveToken midToken = aaveRegistry.aTokenByToken(midPreToken); if (midToken != IAaveToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, 1e18, flags, 310_000, 670_000 ); } } return (new uint256[](parts), 0); } function calculateKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 // 0x63825c174ab367968EC60f061753D3bbD36A0D8F ); } function calculateKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 // 0x7a3370075a54B187d7bD5DceBf0ff2B5552d4F7D ); } function calculateKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 // 0x4f32BbE8dFc9efD54345Fc936f9fEF1048746fCF ); } function calculateKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { bytes32 reserveId = _kyberReserveIdByTokens(fromToken, destToken); if (reserveId == 0) { return (new uint256[](parts), 0); } return _calculateKyber( fromToken, destToken, amount, parts, flags, reserveId ); } function _kyberGetRate( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/, bytes memory hint ) private view returns(uint256) { (, bytes memory data) = address(kyberNetworkProxy).staticcall( abi.encodeWithSelector( kyberNetworkProxy.getExpectedRateAfterFee.selector, fromToken, destToken, amount, 10, hint ) ); return (data.length == 32) ? abi.decode(data, (uint256)) : 0; } function _calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, bytes32 reserveId ) internal view returns(uint256[] memory rets, uint256 gas) { bytes memory fromHint; bytes memory destHint; { bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; (bool success, bytes memory data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildTokenToEthHint.selector, fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); fromHint = success ? abi.decode(data, (bytes)) : bytes(""); (success, data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildEthToTokenHint.selector, destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); destHint = success ? abi.decode(data, (bytes)) : bytes(""); } uint256 fromTokenDecimals = 10 ** IERC20(fromToken).universalDecimals(); uint256 destTokenDecimals = 10 ** IERC20(destToken).universalDecimals(); rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { if (i > 0 && rets[i - 1] == 0) { break; } rets[i] = amount.mul(i + 1).div(parts); if (!fromToken.isETH()) { if (fromHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( fromToken, ETH_ADDRESS, rets[i], flags, fromHint ); rets[i] = rate.mul(rets[i]).div(fromTokenDecimals); } if (!destToken.isETH() && rets[i] > 0) { if (destHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( ETH_ADDRESS, destToken, rets[i], 10, destHint ); rets[i] = rate.mul(rets[i]).mul(destTokenDecimals).div(1e36); } } return (rets, 100_000); } function calculateBancor( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { return (new uint256[](parts), 0); // 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 calculateMooniswapMany( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IMooniswap mooniswap = mooniswapRegistry.pools( fromToken.isETH() ? ZERO_ADDRESS : fromToken, destToken.isETH() ? ZERO_ADDRESS : destToken ); if (mooniswap == IMooniswap(0)) { return (rets, 0); } uint256 fee = mooniswap.fee(); uint256 fromBalance = mooniswap.getBalanceForAddition(fromToken.isETH() ? ZERO_ADDRESS : fromToken); uint256 destBalance = mooniswap.getBalanceForRemoval(destToken.isETH() ? ZERO_ADDRESS : destToken); if (fromBalance == 0 || destBalance == 0) { return (rets, 0); } for (uint i = 0; i < amounts.length; i++) { uint256 amount = amounts[i].sub(amounts[i].mul(fee).div(1e18)); rets[i] = amount.mul(destBalance).div( fromBalance.add(amount) ); } return (rets, (fromToken.isETH() || destToken.isETH()) ? 80_000 : 110_000); } function calculateMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { return calculateMooniswapMany( fromToken, destToken, _linearInterpolation(amount, parts) ); } function calculateMooniswapOverETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken.isETH() || destToken.isETH()) { return (new uint256[](parts), 0); } (uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, ZERO_ADDRESS, amount, parts, flags); (rets, gas) = calculateMooniswapMany(ZERO_ADDRESS, destToken, results); gas = gas.add(gas1); } function calculateMooniswapOverDAI( 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); } (uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, dai, amount, parts, flags); (rets, gas) = calculateMooniswapMany(dai, destToken, results); gas = gas.add(gas1); } function calculateMooniswapOverUSDC( 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); } (uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, usdc, amount, parts, flags); (rets, gas) = calculateMooniswapMany(usdc, destToken, results); gas = gas.add(gas1); } function calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswapV2( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function calculateUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, weth, destToken, amount, parts, flags ); } function calculateUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai || destToken == dai) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, dai, destToken, amount, parts, flags ); } function calculateUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == usdc || destToken == usdc) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, usdc, destToken, amount, parts, flags ); } function _calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 destTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal); if (exchange != IUniswapV2Exchange(0)) { uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange)); uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange)); for (uint i = 0; i < amounts.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]); } return (rets, 50_000); } } function _calculateUniswapV2OverMidToken( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); uint256 gas1; uint256 gas2; (rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags); (rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags); return (rets, gas1 + gas2); } function _calculateNoReturn( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { this; return (new uint256[](parts), 0); } } contract OneSplitBaseWrap is IOneSplit, OneSplitRoot { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) internal { if (fromToken == destToken) { return; } _swapFloor( fromToken, destToken, amount, distribution, flags ); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) internal; } contract OneSplit is IOneSplit, OneSplitRoot { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplitView) public { oneSplitView = _oneSplitView; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) public payable returns(uint256 returnAmount) { if (fromToken == destToken) { return amount; } function(IERC20,IERC20,uint256,uint256)[DEXES_COUNT] memory reserves = [ _swapOnUniswap, _swapOnNowhere, _swapOnBancor, _swapOnOasis, _swapOnCurveCompound, _swapOnCurveUSDT, _swapOnCurveY, _swapOnCurveBinance, _swapOnCurveSynthetix, _swapOnUniswapCompound, _swapOnUniswapChai, _swapOnUniswapAave, _swapOnMooniswap, _swapOnUniswapV2, _swapOnUniswapV2ETH, _swapOnUniswapV2DAI, _swapOnUniswapV2USDC, _swapOnCurvePAX, _swapOnCurveRenBTC, _swapOnCurveTBTC, _swapOnDforceSwap, _swapOnShell, _swapOnMStableMUSD, _swapOnCurveSBTC, _swapOnBalancer1, _swapOnBalancer2, _swapOnBalancer3, _swapOnKyber1, _swapOnKyber2, _swapOnKyber3, _swapOnKyber4, _swapOnMooniswapETH, _swapOnMooniswapDAI, _swapOnMooniswapUSDC ]; require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size"); uint256 parts = 0; uint256 lastNonZeroIndex = 0; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { parts = parts.add(distribution[i]); lastNonZeroIndex = i; } } if (parts == 0) { if (fromToken.isETH()) { msg.sender.transfer(msg.value); return msg.value; } return amount; } fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); for (uint i = 0; i < distribution.length; i++) { if (distribution[i] == 0) { continue; } uint256 swapAmount = amount.mul(distribution[i]).div(parts); if (i == lastNonZeroIndex) { swapAmount = remainingAmount; } remainingAmount -= swapAmount; reserves[i](fromToken, destToken, swapAmount, flags); } returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: Return amount was not enough"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } // Swap helpers function _swapOnCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveCompound), amount); curveCompound.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveUSDT), amount); curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == tusd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == tusd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveY), amount); curveY.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == busd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == busd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveBinance), amount); curveBinance.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == susd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == susd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveSynthetix), amount); curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == pax ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == pax ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curvePAX), amount); curvePAX.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(shell), amount); shell.swapByOrigin( address(fromToken), address(destToken), amount, 0, now + 50 ); } function _swapOnMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } function _swapOnCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveRenBTC), amount); curveRenBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == tbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == hbtc ? 3 : 0); int128 j = (destToken == tbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == hbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveTBTC), amount); curveTBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == sbtc ? 3 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == sbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveSBTC), amount); curveSBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(dforceSwap), amount); dforceSwap.swap(fromToken, destToken, amount); } function _swapOnUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { fromToken.universalApprove(address(fromExchange), returnAmount); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { ICompoundToken fromCompound = compoundRegistry.cTokenByToken(fromToken); fromToken.universalApprove(address(fromCompound), amount); fromCompound.mint(amount); _swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { ICompoundToken toCompound = compoundRegistry.cTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toCompound), amount, flags); toCompound.redeem(IERC20(toCompound).universalBalanceOf(address(this))); destToken.universalBalanceOf(address(this)); return; } } function _swapOnUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (fromToken == dai) { fromToken.universalApprove(address(chai), amount); chai.join(address(this), amount); _swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this)), flags); return; } if (destToken == dai) { _swapOnUniswap(fromToken, IERC20(chai), amount, flags); chai.exit(address(this), chai.balanceOf(address(this))); return; } } function _swapOnUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { IAaveToken fromAave = aaveRegistry.aTokenByToken(fromToken); fromToken.universalApprove(aave.core(), amount); aave.deposit(fromToken, amount, 1101); _swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { IAaveToken toAave = aaveRegistry.aTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toAave), amount, flags); toAave.redeem(toAave.balanceOf(address(this))); return; } } function _swapOnMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IMooniswap mooniswap = mooniswapRegistry.pools( fromToken.isETH() ? ZERO_ADDRESS : fromToken, destToken.isETH() ? ZERO_ADDRESS : destToken ); fromToken.universalApprove(address(mooniswap), amount); mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken.isETH() ? ZERO_ADDRESS : fromToken, destToken.isETH() ? ZERO_ADDRESS : destToken, amount, 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3 ); } function _swapOnMooniswapETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnMooniswap(fromToken, ZERO_ADDRESS, amount, flags); _swapOnMooniswap(ZERO_ADDRESS, destToken, address(this).balance, flags); } function _swapOnMooniswapDAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnMooniswap(fromToken, dai, amount, flags); _swapOnMooniswap(dai, destToken, dai.balanceOf(address(this)), flags); } function _swapOnMooniswapUSDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnMooniswap(fromToken, usdc, amount, flags); _swapOnMooniswap(usdc, destToken, usdc.balanceOf(address(this)), flags); } function _swapOnNowhere( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*flags*/ ) internal { revert("This source was deprecated"); } function _swapOnKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 ); } function _swapOnKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 ); } function _swapOnKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 ); } function _swapOnKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, _kyberReserveIdByTokens(fromToken, destToken) ); } function _swapOnKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/, bytes32 reserveId ) internal { uint256 returnAmount = amount; bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; if (!fromToken.isETH()) { bytes memory fromHint = kyberHintHandler.buildTokenToEthHint( fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); fromToken.universalApprove(address(kyberNetworkProxy), amount); returnAmount = kyberNetworkProxy.tradeWithHintAndFee( fromToken, returnAmount, ETH_ADDRESS, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, 10, fromHint ); } if (!destToken.isETH()) { bytes memory destHint = kyberHintHandler.buildEthToTokenHint( destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); returnAmount = kyberNetworkProxy.tradeWithHintAndFee.value(returnAmount)( ETH_ADDRESS, returnAmount, destToken, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, 10, destHint ); } } function _swapOnBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorNetworkPathFinder.generatePath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); fromToken.universalApprove(address(bancorNetwork), amount); bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1); } function _swapOnOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 approveToken = fromToken.isETH() ? weth : fromToken; approveToken.universalApprove(address(oasisExchange), amount); oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 1 ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal); returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount); fromTokenReal.universalTransfer(address(exchange), amount); if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) { exchange.swap(0, returnAmount, address(this), ""); } else { exchange.swap(returnAmount, 0, address(this), ""); } if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( midToken, destToken, _swapOnUniswapV2Internal( fromToken, midToken, amount, flags ), flags ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( fromToken, destToken, amount, flags ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, weth, destToken, amount, flags ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, dai, destToken, amount, flags ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, usdc, destToken, amount, flags ); } function _swapOnBalancerX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/, uint256 poolIndex ) internal { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (fromToken.isETH()) { weth.deposit.value(amount)(); } (fromToken.isETH() ? weth : fromToken).universalApprove(pools[poolIndex], amount); IBalancerPool(pools[poolIndex]).swapExactAmountIn( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 0, uint256(-1) ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 0); } function _swapOnBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 1); } function _swapOnBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 2); } } // File: contracts/OneSplitCompound.sol pragma solidity ^0.5.0; contract OneSplitCompoundView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn( underlying, destToken, amount.mul(compoundRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18) ); return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitCompound is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compoundSwap( fromToken, destToken, amount, distribution, flags ); } function _compoundSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { ICompoundToken(address(fromToken)).redeem(amount); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return _compoundSwap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { cETH.mint.value(underlyingAmount)(); } else { underlying.universalApprove(address(destToken), underlyingAmount); ICompoundToken(address(destToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IFulcrum.sol pragma solidity ^0.5.0; contract IFulcrumToken is IERC20 { function tokenPrice() external view returns (uint256); function loanTokenAddress() external view returns (address); function mintWithEther(address receiver) external payable returns (uint256 mintAmount); function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount); function burnToEther(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); } // File: contracts/OneSplitFulcrum.sol pragma solidity ^0.5.0; contract OneSplitFulcrumBase { using UniversalERC20 for IERC20; function _isFulcrumToken(IERC20 token) internal view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature( "name()" )); if (!success) { return IERC20(-1); } bool foundBZX = false; for (uint i = 0; i + 6 < data.length; i++) { if (data[i + 0] == "F" && data[i + 1] == "u" && data[i + 2] == "l" && data[i + 3] == "c" && data[i + 4] == "r" && data[i + 5] == "u" && data[i + 6] == "m") { foundBZX = true; break; } } if (!foundBZX) { return IERC20(-1); } (success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( IFulcrumToken(address(token)).loanTokenAddress.selector )); if (!success) { return IERC20(-1); } return abi.decode(data, (IERC20)); } } contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn( underlying, destToken, amount.mul(fulcrumRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 381_000, distribution); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18) ); return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, destToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { if (underlying.isETH()) { IFulcrumToken(address(fromToken)).burnToEther(address(this), amount); } else { IFulcrumToken(address(fromToken)).burn(address(this), amount); } uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return super._swap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { underlying.universalApprove(address(destToken), underlyingAmount); IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, chai.chaiToDai(amount), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 197_000, distribution); } if (destToken == IERC20(chai)) { uint256 price = chai.chaiPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(1e18).div(price) ); return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } if (destToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(chai), daiBalance); chai.join(address(this), daiBalance); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IBdai.sol pragma solidity ^0.5.0; contract IBdai is IERC20 { function join(uint256) external; function exit(uint256) external; } // File: contracts/OneSplitBdai.sol pragma solidity ^0.5.0; contract OneSplitBdaiBase { IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 227_000, distribution); } if (destToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { bdai.exit(amount); uint256 btuBalance = btu.balanceOf(address(this)); if (btuBalance > 0) { (,uint256[] memory btuDistribution) = getExpectedReturn( btu, destToken, btuBalance, 1, flags ); _swap( btu, destToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, destToken, amount, distribution, flags ); } if (destToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(bdai), daiBalance); bdai.join(daiBalance); return; } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIearn.sol pragma solidity ^0.5.0; contract IIearn is IERC20 { function token() external view returns(IERC20); function calcPoolValueInToken() external view returns(uint256); function deposit(uint256 _amount) external; function withdraw(uint256 _shares) external; } // File: contracts/OneSplitIearn.sol pragma solidity ^0.5.0; contract OneSplitIearnBase { function _yTokens() internal pure returns(IIearn[13] memory) { return [ IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01), IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9), IIearn(0x73a052500105205d34Daf004eAb301916DA8190f), IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D), IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e), IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600), IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE), IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32), IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447), IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951), IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc), IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E), IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59) ]; } } contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _iearnGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { (returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn( yTokens[i].token(), destToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 260_000, distribution); } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; IERC20 token = yTokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()) ); return( returnAmount .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), estimateGasAmount + 743_000, distribution ); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, destToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(yTokens[i]), underlyingBalance); yTokens[i].deposit(underlyingBalance); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIdle.sol pragma solidity ^0.5.0; contract IIdle is IERC20 { function token() external view returns (IERC20); function tokenPrice() external view returns (uint256); function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts) external returns (uint256 mintedTokens); function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts) external returns (uint256 redeemedTokens); } // File: contracts/OneSplitIdle.sol pragma solidity ^0.5.0; contract OneSplitIdleBase { function _idleTokens() internal pure returns(IIdle[8] memory) { // https://developers.idle.finance/contracts-and-codebase return [ // V3 IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934), IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6), IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D), IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB), IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C), IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B), // V2 IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _idleGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { (returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn( tokens[i].token(), destToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 2_400_000, distribution); } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 _price = tokens[i].tokenPrice(); IERC20 token = tokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(_price).div(1e18) ); return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, destToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0)); _idleSwap(underlying, destToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(tokens[i]), underlyingBalance); tokens[i].mintIdleToken(underlyingBalance, new uint256[](0)); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/OneSplitAave.sol pragma solidity ^0.5.0; contract OneSplitAaveView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn( underlying, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 670_000, distribution); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 310_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitAave is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, destToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, destToken, amount, distribution, flags ); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); underlying.universalApprove(aave.core(), underlyingAmount); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice); } if (destToken == weth || destToken == bancorEtherToken) { return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, destToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (destToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (destToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitMStable.sol pragma solidity ^0.5.0; contract OneSplitMStableView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { { (bool valid1,, uint256 res1,) = musd_helper.getRedeemValidity(musd, amount, destToken); if (valid1) { return (res1, 300_000, new uint256[](DEXES_COUNT)); } } (bool valid,, address token) = musd_helper.suggestRedeemAsset(musd); if (valid) { (,, returnAmount,) = musd_helper.getRedeemValidity(musd, amount, IERC20(token)); if (IERC20(token) != destToken) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( IERC20(token), destToken, returnAmount, parts, flags, destTokenEthPriceTimesGasPrice ); } else { distribution = new uint256[](DEXES_COUNT); } 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; (bool valid,, address token) = musd_helper.suggestMintAsset(_destToken); if (valid) { if (IERC20(token) != fromToken) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, IERC20(token), amount, parts, flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, IERC20(token), destTokenEthPriceTimesGasPrice ) ); } else { returnAmount = amount; } (,, returnAmount) = musd.getSwapOutput(IERC20(token), _destToken, returnAmount); 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: @openzeppelin/contracts/math/Math.sol pragma solidity ^0.5.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // File: contracts/OneSplitMooniswapPoolToken.sol pragma solidity ^0.5.0; contract OneSplitMooniswapTokenBase { using SafeMath for uint256; using Math for uint256; using UniversalERC20 for IERC20; struct TokenInfo { IERC20 token; uint256 reserve; } struct PoolDetails { TokenInfo[2] tokens; uint256 totalSupply; } function _getPoolDetails(IMooniswap pool) internal view returns (PoolDetails memory details) { for (uint i = 0; i < 2; i++) { IERC20 token = pool.tokens(i); details.tokens[i] = TokenInfo({ token: token, reserve: token.universalBalanceOf(address(pool)) }); } details.totalSupply = IERC20(address(pool)).totalSupply(); } } contract OneSplitMooniswapTokenView is OneSplitViewWrapBase, OneSplitMooniswapTokenBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns ( uint256 returnAmount, uint256, uint256[] memory distribution ) { if (fromToken.eq(toToken)) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_MOONISWAP_POOL_TOKEN)) { bool isPoolTokenFrom = mooniswapRegistry.isPool(address(fromToken)); bool isPoolTokenTo = mooniswapRegistry.isPool(address(toToken)); if (isPoolTokenFrom && isPoolTokenTo) { ( uint256 returnETHAmount, uint256[] memory poolTokenFromDistribution ) = _getExpectedReturnFromMooniswapPoolToken( fromToken, ETH_ADDRESS, amount, parts, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); ( uint256 returnPoolTokenToAmount, uint256[] memory poolTokenToDistribution ) = _getExpectedReturnToMooniswapPoolToken( ETH_ADDRESS, toToken, returnETHAmount, parts, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); for (uint i = 0; i < poolTokenToDistribution.length; i++) { poolTokenFromDistribution[i] |= poolTokenToDistribution[i] << 128; } return (returnPoolTokenToAmount, 0, poolTokenFromDistribution); } if (isPoolTokenFrom) { (returnAmount, distribution) = _getExpectedReturnFromMooniswapPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); return (returnAmount, 0, distribution); } if (isPoolTokenTo) { (returnAmount, distribution) = _getExpectedReturnToMooniswapPoolToken( fromToken, toToken, amount, parts, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); return (returnAmount, 0, distribution); } } return super.getExpectedReturnWithGas( fromToken, toToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnFromMooniswapPoolToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); PoolDetails memory details = _getPoolDetails(IMooniswap(address(poolToken))); for (uint i = 0; i < 2; i++) { uint256 exchangeAmount = amount .mul(details.tokens[i].reserve) .div(details.totalSupply); if (toToken.eq(details.tokens[i].token)) { returnAmount = returnAmount.add(exchangeAmount); continue; } (uint256 ret, ,uint256[] memory dist) = super.getExpectedReturnWithGas( details.tokens[i].token, toToken, exchangeAmount, parts, flags, 0 ); returnAmount = returnAmount.add(ret); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } return (returnAmount, distribution); } function _getExpectedReturnToMooniswapPoolToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256 parts, uint256 flags ) private view returns( uint256 returnAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); PoolDetails memory details = _getPoolDetails(IMooniswap(address(poolToken))); // will overwritten to liquidity amounts uint256[2] memory amounts; amounts[0] = amount.div(2); amounts[1] = amount.sub(amounts[0]); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { if (fromToken.eq(details.tokens[i].token)) { continue; } (amounts[i], ,dist) = super.getExpectedReturnWithGas( fromToken, details.tokens[i].token, amounts[i], parts, flags, 0 ); for (uint j = 0; j < distribution.length; j++) { distribution[j] |= dist[j] << (i * 8); } } returnAmount = uint256(-1); for (uint i = 0; i < 2; i++) { returnAmount = Math.min( returnAmount, details.totalSupply.mul(amounts[i]).div(details.tokens[i].reserve) ); } return ( returnAmount, distribution ); } } contract OneSplitMooniswapToken is OneSplitBaseWrap, OneSplitMooniswapTokenBase { function _swap( IERC20 fromToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken.eq(toToken)) { return; } if (!flags.check(FLAG_DISABLE_MOONISWAP_POOL_TOKEN)) { bool isPoolTokenFrom = mooniswapRegistry.isPool(address(fromToken)); bool isPoolTokenTo = mooniswapRegistry.isPool(address(toToken)); if (isPoolTokenFrom && isPoolTokenTo) { uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] & ((1 << 128) - 1); } uint256 ethBalanceBefore = ETH_ADDRESS.universalBalanceOf(address(this)); _swapFromMooniswapToken( fromToken, ETH_ADDRESS, amount, dist, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); for (uint i = 0; i < distribution.length; i++) { dist[i] = distribution[i] >> 128; } uint256 ethBalanceAfter = ETH_ADDRESS.universalBalanceOf(address(this)); return _swapToMooniswapToken( ETH_ADDRESS, toToken, ethBalanceAfter.sub(ethBalanceBefore), dist, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); } if (isPoolTokenFrom) { return _swapFromMooniswapToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); } if (isPoolTokenTo) { return _swapToMooniswapToken( fromToken, toToken, amount, distribution, FLAG_DISABLE_MOONISWAP_POOL_TOKEN ); } } return super._swap( fromToken, toToken, amount, distribution, flags ); } function _swapFromMooniswapToken( IERC20 poolToken, IERC20 toToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { IERC20[2] memory tokens = [ IMooniswap(address(poolToken)).tokens(0), IMooniswap(address(poolToken)).tokens(1) ]; IMooniswap(address(poolToken)).withdraw( amount, new uint256[](0) ); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { if (toToken.eq(tokens[i])) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } super._swap( tokens[i], toToken, tokens[i].universalBalanceOf(address(this)), dist, flags ); } } function _swapToMooniswapToken( IERC20 fromToken, IERC20 poolToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { IERC20[2] memory tokens = [ IMooniswap(address(poolToken)).tokens(0), IMooniswap(address(poolToken)).tokens(1) ]; // will overwritten to liquidity amounts uint256[] memory amounts = new uint256[](2); amounts[0] = amount.div(2); amounts[1] = amount.sub(amounts[0]); uint256[] memory dist = new uint256[](distribution.length); for (uint i = 0; i < 2; i++) { if (fromToken.eq(tokens[i])) { continue; } for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (i * 8)) & 0xFF; } super._swap( fromToken, tokens[i], amounts[i], dist, flags ); amounts[i] = tokens[i].universalBalanceOf(address(this)); tokens[i].universalApprove(address(poolToken), amounts[i]); } uint256 ethValue = (tokens[0].isETH() ? amounts[0] : 0) + (tokens[1].isETH() ? amounts[1] : 0); IMooniswap(address(poolToken)).deposit.value(ethValue)( amounts, 0 ); for (uint i = 0; i < 2; i++) { tokens[i].universalTransfer( msg.sender, tokens[i].universalBalanceOf(address(this)) ); } } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMStableView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, OneSplitDMMView, OneSplitMooniswapTokenView { 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, OneSplitMooniswapToken { IOneSplitView public oneSplitView; IOneSplit public oneSplit; constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public { oneSplitView = _oneSplitView; oneSplit = _oneSplit; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ) { uint256[] memory dist; returnAmounts = new uint256[](tokens.length - 1); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { returnAmounts[i - 1] = (i == 1) ? amount : returnAmounts[i - 2]; continue; } IERC20[] memory _tokens = tokens; ( returnAmounts[i - 1], amount, dist ) = getExpectedReturnWithGas( _tokens[i - 1], _tokens[i], (i == 1) ? amount : returnAmounts[i - 2], parts[i - 1], flags[i - 1], destTokenEthPriceTimesGasPrices[i - 1] ); estimateGasAmount = estimateGasAmount.add(amount); if (distribution.length == 0) { distribution = new uint256[](dist.length); } for (uint j = 0; j < distribution.length; j++) { distribution[j] = distribution[j].add(dist[j] << (8 * (i - 1))); } } } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount) { fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 confirmed = fromToken.universalBalanceOf(address(this)); _swap(fromToken, destToken, confirmed, distribution, flags); returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount) { tokens[0].universalTransferFrom(msg.sender, address(this), amount); returnAmount = tokens[0].universalBalanceOf(address(this)); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } uint256[] memory dist = new uint256[](distribution.length); for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (8 * (i - 1))) & 0xFF; } _swap( tokens[i - 1], tokens[i], returnAmount, dist, flags[i - 1] ); 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
608060405234801561001057600080fd5b50604051620053a5380380620053a58339818101604052604081101561003557600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b03199182161790915560018054939092169216919091179055615328806200007d6000396000f3fe6080604052600436106100705760003560e01c80638373f2651161004e5780638373f26514610436578063c7851396146104ed578063e2a7515e146106b0578063fbe4ed951461077857610070565b8063085e2c5b1461007f57806343ee21f0146101295780637b33701a1461015a575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b0381358116916020810135909116906040810135906060810135906080013561078d565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b34801561013557600080fd5b5061013e6107b0565b604080516001600160a01b039092168252519081900360200190f35b34801561016657600080fd5b50610396600480360360a081101561017d57600080fd5b810190602081018135600160201b81111561019757600080fd5b8201836020820111156101a957600080fd5b803590602001918460208302840111600160201b831117156101ca57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561022157600080fd5b82018360208201111561023357600080fd5b803590602001918460208302840111600160201b8311171561025457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460208302840111600160201b831117156102d657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561032557600080fd5b82018360208201111561033757600080fd5b803590602001918460208302840111600160201b8311171561035857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107bf945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b838110156103e05781810151838201526020016103c8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561041f578181015183820152602001610407565b505050509050019550505050505060405180910390f35b34801561044257600080fd5b5061048b600480360360c081101561045957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a20565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156104d75781810151838201526020016104bf565b5050505090500194505050505060405180910390f35b61069e600480360360a081101561050357600080fd5b810190602081018135600160201b81111561051d57600080fd5b82018360208201111561052f57600080fd5b803590602001918460208302840111600160201b8311171561055057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156105ab57600080fd5b8201836020820111156105bd57600080fd5b803590602001918460208302840111600160201b831117156105de57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561062d57600080fd5b82018360208201111561063f57600080fd5b803590602001918460208302840111600160201b8311171561066057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610b77945050505050565b60408051918252519081900360200190f35b61069e600480360360c08110156106c657600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561070557600080fd5b82018360208201111561071757600080fd5b803590602001918460208302840111600160201b8311171561073857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610dbd915050565b34801561078457600080fd5b5061013e610eb9565b600060606107a087878787876000610a20565b9199919850909650505050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156107f4578160200160208202803883390190505b50935060015b8951811015610a135789818151811061080f57fe5b60200260200101516001600160a01b03168a600183038151811061082f57fe5b60200260200101516001600160a01b0316141561088c578060011461086a5784600282038151811061085d57fe5b602002602001015161086c565b885b85600183038151811061087b57fe5b602002602001018181525050610a0b565b60608a905061092f8160018403815181106108a357fe5b60200260200101518284815181106108b757fe5b6020026020010151846001146108e3578860028603815181106108d657fe5b60200260200101516108e5565b8c5b8c60018703815181106108f457fe5b60200260200101518c600188038151811061090b57fe5b60200260200101518c600189038151811061092257fe5b6020026020010151610a20565b88600186038151811061093e57fe5b60209081029190910101929092529a509250610960858b63ffffffff610ec816565b945083516000141561099b578251604051908082528060200260200182016040528015610997578160200160208202803883390190505b5093505b60005b8451811015610a08576109e9600184036008028583815181106109bd57fe5b6020026020010151901b8683815181106109d357fe5b6020026020010151610ec890919063ffffffff16565b8582815181106109f557fe5b602090810291909101015260010161099e565b50505b6001016107fa565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610a9357600080fd5b505afa158015610aa7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610ad057600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610afa57600080fd5b908301906020820185811115610b0f57600080fd5b82518660208202830111600160201b82111715610b2b57600080fd5b82525081516020918201928201910280838360005b83811015610b58578181015183820152602001610b40565b5050505090500160405250505092509250925096509650969350505050565b6000610bad33308789600081518110610b8c57fe5b60200260200101516001600160a01b0316610f2b909392919063ffffffff16565b610bdd3087600081518110610bbe57fe5b60200260200101516001600160a01b031661104a90919063ffffffff16565b905060015b8651811015610d5e57868181518110610bf757fe5b60200260200101516001600160a01b0316876001830381518110610c1757fe5b60200260200101516001600160a01b03161415610c3357610d56565b60608451604051908082528060200260200182016040528015610c60578160200160208202803883390190505b50905060005b8551811015610cae5760018303600802868281518110610c8257fe5b6020026020010151901c60ff16828281518110610c9b57fe5b6020908102919091010152600101610c66565b50610cfb886001840381518110610cc157fe5b6020026020010151898481518110610cd557fe5b60200260200101518584886001880381518110610cee57fe5b60200260200101516110f4565b610d0b30898481518110610bbe57fe5b9250610d5333610d24308b6001870381518110610bbe57fe5b8a6001860381518110610d3357fe5b60200260200101516001600160a01b031661141b9092919063ffffffff16565b50505b600101610be2565b5083811015610d9e5760405162461bcd60e51b81526004018080602001828103825260358152602001806152146035913960400191505060405180910390fd5b610db333828860018a510381518110610d3357fe5b5095945050505050565b6000610dda6001600160a01b03881633308863ffffffff610f2b16565b6000610df56001600160a01b0389163063ffffffff61104a16565b9050610e0488888387876110f4565b610e1d6001600160a01b0388163063ffffffff61104a16565b915084821015610e5e5760405162461bcd60e51b81526004018080602001828103825260358152602001806152146035913960400191505060405180910390fd5b610e786001600160a01b038816338463ffffffff61141b16565b50610ead33610e966001600160a01b038b163063ffffffff61104a16565b6001600160a01b038b16919063ffffffff61141b16565b50509695505050505050565b6000546001600160a01b031681565b600082820183811015610f22576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b80610f3557611044565b610f3e84611499565b15611029576001600160a01b03831633148015610f5b5750803410155b610f965760405162461bcd60e51b815260040180806020018281038252602b815260200180615269602b913960400191505060405180910390fd5b6001600160a01b0382163014610fde576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fdc573d6000803e3d6000fd5b505b8034111561102457336108fc610ffa348463ffffffff6114d516565b6040518115909202916000818181858888f19350505050158015611022573d6000803e3d6000fd5b505b611044565b6110446001600160a01b03851684848463ffffffff61151716565b50505050565b600061105583611499565b1561106b57506001600160a01b03811631610f25565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110c157600080fd5b505afa1580156110d5573d6000803e3d6000fd5b505050506040513d60208110156110eb57600080fd5b50519050610f25565b61110d6001600160a01b0386168563ffffffff61157116565b1561111757611414565b61112b81600160431b63ffffffff6115a716565b6114075760408051635b16ebb760e01b81526001600160a01b0387166004820152905160009173c12a7e093832e2d2267df225baca60bd2b74c65f91635b16ebb791602480820192602092909190829003018186803b15801561118d57600080fd5b505afa1580156111a1573d6000803e3d6000fd5b505050506040513d60208110156111b757600080fd5b505160408051635b16ebb760e01b81526001600160a01b0388166004820152905191925060009173c12a7e093832e2d2267df225baca60bd2b74c65f91635b16ebb7916024808301926020929190829003018186803b15801561121957600080fd5b505afa15801561122d573d6000803e3d6000fd5b505050506040513d602081101561124357600080fd5b505190508180156112515750805b156113cf5760608451604051908082528060200260200182016040528015611283578160200160208202803883390190505b50905060005b85518110156112d75785818151811061129e57fe5b60200260200101516fffffffffffffffffffffffffffffffff168282815181106112c457fe5b6020908102919091010152600101611289565b5060006112fe73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3063ffffffff61104a16565b90506113258973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8985600160431b6115ad565b60005b865181101561136857608087828151811061133f57fe5b6020026020010151901c83828151811061135557fe5b6020908102919091010152600101611328565b50600061138f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3063ffffffff61104a16565b90506113c573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8a6113ba848663ffffffff6114d516565b86600160431b611872565b5050505050611414565b81156113ed576113e687878787600160431b6115ad565b5050611414565b8015611404576113e687878787600160431b611872565b50505b6114148585858585611ce3565b5050505050565b60008161142a57506001611492565b61143384611499565b15611474576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561146e573d6000803e3d6000fd5b50611492565b61148e6001600160a01b038516848463ffffffff611cf016565b5060015b9392505050565b60006001600160a01b03821615806114cd57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b6000610f2283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d47565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611044908590611dde565b6000816001600160a01b0316836001600160a01b03161480610f22575061159783611499565b8015610f225750610f2282611499565b16151590565b6115b56151b7565b604080518082018083526327b2595f60e11b905260006044820152905181906001600160a01b03891690634f64b2be90606480850191602091818703018186803b15801561160257600080fd5b505afa158015611616573d6000803e3d6000fd5b505050506040513d602081101561162c57600080fd5b50516001600160a01b039081168252604080516327b2595f60e11b8152600160048201529051602093840193928b1692634f64b2be9260248082019391829003018186803b15801561167d57600080fd5b505afa158015611691573d6000803e3d6000fd5b505050506040513d60208110156116a757600080fd5b50516001600160a01b039081169091526040805160008082526020808301808552632c8aec0360e11b8152602484018b815260448501958652845160648601819052979850958d1696635915d806968c969094909360848701939202908190849084905b8381101561172357818101518382015260200161170b565b505050509050019350505050600060405180830381600087803b15801561174957600080fd5b505af115801561175d573d6000803e3d6000fd5b505050506060835160405190808252806020026020018201604052801561178e578160200160208202803883390190505b50905060005b6002811015611868576117c78382600281106117ac57fe5b60200201516001600160a01b0389169063ffffffff61157116565b156117d157611860565b60005b855181101561181957816008028682815181106117ed57fe5b6020026020010151901c60ff1683828151811061180657fe5b60209081029190910101526001016117d4565b5061186083826002811061182957fe5b6020020151886118593087866002811061183f57fe5b60200201516001600160a01b03169063ffffffff61104a16565b8588611ce3565b600101611794565b5050505050505050565b61187a6151b7565b604080518082018083526327b2595f60e11b905260006044820152905181906001600160a01b03881690634f64b2be90606480850191602091818703018186803b1580156118c757600080fd5b505afa1580156118db573d6000803e3d6000fd5b505050506040513d60208110156118f157600080fd5b50516001600160a01b039081168252604080516327b2595f60e11b8152600160048201529051602093840193928a1692634f64b2be9260248082019391829003018186803b15801561194257600080fd5b505afa158015611956573d6000803e3d6000fd5b505050506040513d602081101561196c57600080fd5b50516001600160a01b031690526040805160028082526060808301845293945090916020830190803883390190505090506119ae85600263ffffffff611f9616565b816000815181106119bb57fe5b6020026020010181815250506119ee816000815181106119d757fe5b6020026020010151866114d590919063ffffffff16565b816001815181106119fb57fe5b60200260200101818152505060608451604051908082528060200260200182016040528015611a34578160200160208202803883390190505b50905060005b6002811015611b5f57611a6d848260028110611a5257fe5b60200201516001600160a01b038b169063ffffffff61157116565b15611a7757611b57565b60005b8651811015611abf5781600802878281518110611a9357fe5b6020026020010151901c60ff16838281518110611aac57fe5b6020908102919091010152600101611a7a565b50611af089858360028110611ad057fe5b6020020151858481518110611ae157fe5b60200260200101518589611ce3565b611b003085836002811061183f57fe5b838281518110611b0c57fe5b602002602001018181525050611b5788848381518110611b2857fe5b6020026020010151868460028110611b3c57fe5b60200201516001600160a01b0316919063ffffffff611fd816565b600101611a3a565b506000611b7c8460015b60200201516001600160a01b0316611499565b611b87576000611b9d565b82600181518110611b9457fe5b60200260200101515b611ba8856000611b69565b611bb3576000611bc9565b83600081518110611bc057fe5b60200260200101515b019050876001600160a01b0316635dc55f2f828560006040518463ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015611c34578181015183820152602001611c1c565b5050505090500193505050506020604051808303818588803b158015611c5957600080fd5b505af1158015611c6d573d6000803e3d6000fd5b50505050506040513d6020811015611c8457600080fd5b50600090505b6002811015611cd757611cce33611ca73088856002811061183f57fe5b878460028110611cb357fe5b60200201516001600160a01b0316919063ffffffff61141b16565b50600101611c8a565b50505050505050505050565b61141485858585856120cc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d42908490611dde565b505050565b60008184841115611dd65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611d9b578181015183820152602001611d83565b50505050905090810190601f168015611dc85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b611df0826001600160a01b031661241a565b611e41576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310611e7f5780518252601f199092019160209182019101611e60565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ee1576040519150601f19603f3d011682016040523d82523d6000602084013e611ee6565b606091505b509150915081611f3d576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561104457808060200190516020811015611f5957600080fd5b50516110445760405162461bcd60e51b815260040180806020018281038252602a815260200180615294602a913960400191505060405180910390fd5b6000610f2283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612456565b611fe183611499565b611d42578061200a576120056001600160a01b03841683600063ffffffff6124bb16565b611d42565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d602081101561208557600080fd5b50519050818110156110445780156120b2576120b26001600160a01b03851684600063ffffffff6124bb16565b6110446001600160a01b038516848463ffffffff6124bb16565b836001600160a01b0316856001600160a01b031614156120eb57611414565b612101816508000000000063ffffffff6115a716565b151561211782634000000063ffffffff6115a716565b1515141561240d57600061212a866125ce565b90506001600160a01b03808216146122b257856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561218257600080fd5b505af1158015612196573d6000803e3d6000fd5b505050506040513d60208110156121ac57600080fd5b50600090506121ca6001600160a01b0383163063ffffffff61104a16565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156122645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561224b57600080fd5b505af115801561225f573d6000803e3d6000fd5b505050505b6122b06001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461229157826122a7565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b878387876120cc565b505b6122bb856125ce565b90506001600160a01b038082161461240b57612319866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146122fb5782612311565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686612702565b6000612374306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214612349578361235f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff61104a16565b90505b6123916001600160a01b038316878363ffffffff611fd816565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156123d757600080fd5b505af11580156123eb573d6000803e3d6000fd5b505050506040513d602081101561240157600080fd5b5061141492505050565b505b6114148585858585612702565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061244e57508115155b949350505050565b600081836124a55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611d9b578181015183820152602001611d83565b5060008385816124b157fe5b0495945050505050565b801580612541575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561251357600080fd5b505afa158015612527573d6000803e3d6000fd5b505050506040513d602081101561253d57600080fd5b5051155b61257c5760405162461bcd60e51b81526004018080602001828103825260368152602001806152be6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611d42908490611dde565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b6020831061265c5780518252601f19909201916020918201910161263d565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126bc576040519150601f19603f3d011682016040523d82523d6000602084013e6126c1565b606091505b50915091508115806126d257508051155b156126e357600019925050506114d0565b8080602001905160208110156126f857600080fd5b5051949350505050565b61141485858585855b836001600160a01b0316856001600160a01b0316141561272a57611414565b61273d816208000063ffffffff6115a716565b151561275382634000000063ffffffff6115a716565b15151415612a3d576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2141561288157604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156127d957600080fd5b505afa1580156127ed573d6000803e3d6000fd5b505050506040513d602081101561280357600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561284357600080fd5b505af1158015612857573d6000803e3d6000fd5b5050505061287c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585612a46565b611414565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce31514156128ff57604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156127d957600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156129a8576129458573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858561270b565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561299457600080fd5b505af11580156113c5573d6000803e3d6000fd5b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415612a3d576129ee8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858561270b565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561299457600080fd5b61141485858585855b61141485858585855b612a62816280000063ffffffff6115a716565b15612a7782634000000063ffffffff6115a716565b151415612ec957612a866151d5565b612a8e612ed6565b905060005b6008811015612c6157818160088110612aa857fe5b60200201516001600160a01b0316876001600160a01b03161415612c59576000828260088110612ad457fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b1157600080fd5b505afa158015612b25573d6000803e3d6000fd5b505050506040513d6020811015612b3b57600080fd5b505190506000838360088110612b4d57fe5b60200201516001600160a01b031663c85c93aa8860016000604051908082528060200260200182016040528015612b8e578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015612bee578181015183820152602001612bd6565b50505050905001945050505050602060405180830381600087803b158015612c1557600080fd5b505af1158015612c29573d6000803e3d6000fd5b505050506040513d6020811015612c3f57600080fd5b50519050612c508289838989612a4f565b50505050611414565b600101612a93565b5060005b6008811015612ec657818160088110612c7a57fe5b60200201516001600160a01b0316866001600160a01b03161415612ebe576000828260088110612ca657fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ce357600080fd5b505afa158015612cf7573d6000803e3d6000fd5b505050506040513d6020811015612d0d57600080fd5b50519050612d1e8882888888612fbc565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b158015612d6857600080fd5b505afa158015612d7c573d6000803e3d6000fd5b505050506040513d6020811015612d9257600080fd5b50519050612dc1848460088110612da557fe5b60200201516001600160a01b038416908363ffffffff611fd816565b838360088110612dcd57fe5b60200201516001600160a01b0316633cfcef64826000604051908082528060200260200182016040528015612e0c578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015612e62578181015183820152602001612e4a565b505050509050019350505050602060405180830381600087803b158015612e8857600080fd5b505af1158015612e9c573d6000803e3d6000fd5b505050506040513d6020811015612eb257600080fd5b50611414945050505050565b600101612c65565b50505b6114148585858585612fbc565b612ede6151d5565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b61141485858585855b836001600160a01b0316856001600160a01b03161415612fe457611414565b612ff68161080063ffffffff6115a716565b151561300c82634000000063ffffffff6115a716565b151514156133a75761301c6151f4565b6130246133b4565b905060005b600d8110156131e1578181600d811061303e57fe5b60200201516001600160a01b0316876001600160a01b031614156131d95760008282600d811061306a57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156130a757600080fd5b505afa1580156130bb573d6000803e3d6000fd5b505050506040513d60208110156130d157600080fd5b505190508282600d81106130e157fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561312b57600080fd5b505af115801561313f573d6000803e3d6000fd5b505050506131d18188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561319e57600080fd5b505afa1580156131b2573d6000803e3d6000fd5b505050506040513d60208110156131c857600080fd5b50518888612fc5565b505050611414565b600101613029565b5060005b600d8110156133a4578181600d81106131fa57fe5b60200201516001600160a01b0316866001600160a01b0316141561339c5760008282600d811061322657fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561326357600080fd5b505afa158015613277573d6000803e3d6000fd5b505050506040513d602081101561328d57600080fd5b5051905061329e8882888888613521565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156132e857600080fd5b505afa1580156132fc573d6000803e3d6000fd5b505050506040513d602081101561331257600080fd5b505190506133258484600d8110612da557fe5b8383600d811061333157fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561337b57600080fd5b505af115801561338f573d6000803e3d6000fd5b5050505050505050611414565b6001016131e5565b50505b6114148585858585613521565b6133bc6151f4565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b61141485858585855b836001600160a01b0316856001600160a01b0316141561354957611414565b61355a81601063ffffffff6115a716565b151561357082634000000063ffffffff6115a716565b151514156137f75760408051639bbde94760e01b81526001600160a01b0387166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b1580156135d657600080fd5b505afa1580156135ea573d6000803e3d6000fd5b505050506040513d602081101561360057600080fd5b505190506001600160a01b038116156136b057856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561365957600080fd5b505af115801561366d573d6000803e3d6000fd5b505050506040513d602081101561368357600080fd5b50600090506136a16001600160a01b0383163063ffffffff61104a16565b90506113e6828783878761352a565b60408051639bbde94760e01b81526001600160a01b0387166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b15801561370a57600080fd5b505afa15801561371e573d6000803e3d6000fd5b505050506040513d602081101561373457600080fd5b505190506001600160a01b038116156137f5576137548682868686613800565b600061376f6001600160a01b0383163063ffffffff61104a16565b9050613783826001600160a01b0316611499565b1561237757734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156137d757600080fd5b505af11580156137eb573d6000803e3d6000fd5b50505050506113e6565b505b61141485858585855b6114148585858585836001600160a01b0316856001600160a01b0316141561382757611414565b61383881602063ffffffff6115a716565b151561384e82634000000063ffffffff6115a716565b15151415613af557600061386186613b02565b90506001600160a01b03808216146139b157613885816001600160a01b0316611499565b1561390b576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b1580156138d957600080fd5b505af11580156138ed573d6000803e3d6000fd5b505050506040513d602081101561390357600080fd5b506139879050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b15801561395a57600080fd5b505af115801561396e573d6000803e3d6000fd5b505050506040513d602081101561398457600080fd5b50505b60006139a26001600160a01b0383163063ffffffff61104a16565b90506113e68287838787613e78565b6139ba85613b02565b90506001600160a01b0380821614613af3576139d98682868686613e78565b60006139f46001600160a01b0383163063ffffffff61104a16565b9050613a08826001600160a01b0316611499565b15613a8a5760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b158015613a5757600080fd5b505af1158015613a6b573d6000803e3d6000fd5b50505050506040513d6020811015613a8257600080fd5b506113e69050565b613aa46001600160a01b038316878363ffffffff611fd816565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b1580156123d757600080fd5b505b6114148585858585613e78565b6000613b16826001600160a01b0316611499565b15613b2457506000196114d0565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b60208310613b8f5780518252601f199092019160209182019101613b70565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613bf0576040519150601f19603f3d011682016040523d82523d6000602084013e613bf5565b606091505b509150915081613c0b57600019925050506114d0565b6000805b8251816006011015613d6457828160000181518110613c2a57fe5b6020910101516001600160f81b031916602360f91b148015613c6d5750828160010181518110613c5657fe5b6020910101516001600160f81b031916607560f81b145b8015613c9a5750828160020181518110613c8357fe5b6020910101516001600160f81b031916601b60fa1b145b8015613cc75750828160030181518110613cb057fe5b6020910101516001600160f81b031916606360f81b145b8015613cf45750828160040181518110613cdd57fe5b6020910101516001600160f81b031916603960f91b145b8015613d215750828160050181518110613d0a57fe5b6020910101516001600160f81b031916607560f81b145b8015613d4e5750828160060181518110613d3757fe5b6020910101516001600160f81b031916606d60f81b145b15613d5c5760019150613d64565b600101613c0f565b5080613d775760001993505050506114d0565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b60208310613dda5780518252601f199092019160209182019101613dbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613e3b576040519150601f19603f3d011682016040523d82523d6000602084013e613e40565b606091505b50909350915082613e585760001993505050506114d0565b818060200190516020811015613e6d57600080fd5b505195945050505050565b61141485858585855b836001600160a01b0316856001600160a01b03161415613ea057611414565b613eb181608063ffffffff6115a716565b1515613ec782634000000063ffffffff6115a716565b1515141561421157604080516354732ba160e11b81526001600160a01b0387166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b158015613f2d57600080fd5b505afa158015613f41573d6000803e3d6000fd5b505050506040513d6020811015613f5757600080fd5b505190506001600160a01b03811615613fdb57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613fb057600080fd5b505af1158015613fc4573d6000803e3d6000fd5b50505050613fd58186868686613e81565b50611414565b604080516354732ba160e11b81526001600160a01b0387166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b15801561403557600080fd5b505afa158015614049573d6000803e3d6000fd5b505050506040513d602081101561405f57600080fd5b505190506001600160a01b0381161561420f5761407f868286868661421a565b600061409a6001600160a01b0383163063ffffffff61104a16565b905061412f73398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ec57600080fd5b505afa158015614100573d6000803e3d6000fd5b505050506040513d602081101561411657600080fd5b50516001600160a01b038416908363ffffffff611fd816565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e06661415b6001600160a01b038516611499565b614166576000614168565b825b61417a856001600160a01b0316611499565b614184578461419a565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b1580156141ef57600080fd5b505af1158015614203573d6000803e3d6000fd5b50505050505050611414565b505b61141485858585855b836001600160a01b0316856001600160a01b0316141561423957611414565b61424b8161040063ffffffff6115a716565b151561426182634000000063ffffffff6115a716565b15151415614538576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e814156143ee57736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156142e857600080fd5b505af11580156142fc573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b15801561435557600080fd5b505afa158015614369573d6000803e3d6000fd5b505050506040513d602081101561437f57600080fd5b5051905080156143d35760606143ad73b683d83a532e2cb7dfa5275eed3698436371cc9f878460018761078d565b9150506143d173b683d83a532e2cb7dfa5275eed3698436371cc9f878484876110f4565b505b613fd560008051602061524983398151915286868686614541565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e814156145385761442e85600080516020615249833981519152858585614541565b604080516370a0823160e01b81523060048201529051600091600080516020615249833981519152916370a0823191602480820192602092909190829003018186803b15801561447d57600080fd5b505afa158015614491573d6000803e3d6000fd5b505050506040513d60208110156144a757600080fd5b505190506144de600080516020615249833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff611fd816565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561299457600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561456057611414565b61457181604063ffffffff6115a716565b151561458782634000000063ffffffff6115a716565b151514156147f5576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c21514156146ac576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b15801561460d57600080fd5b505af1158015614621573d6000803e3d6000fd5b5050604080516370a0823160e01b8152306004820152905161287c93506000805160206152498339815191529250879183916370a0823191602480820192602092909190829003018186803b15801561467957600080fd5b505afa15801561468d573d6000803e3d6000fd5b505050506040513d60208110156146a357600080fd5b505185856147fe565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c21514156147f5576146ec856000805160206152498339815191528585856147fe565b604080516370a0823160e01b81523060048201529051600091600080516020615249833981519152916370a0823191602480820192602092909190829003018186803b15801561473b57600080fd5b505afa15801561474f573d6000803e3d6000fd5b505050506040513d602081101561476557600080fd5b5051905061479c6000805160206152498339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff611fd816565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b15801561299457600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561481d57611414565b614833816502000000000063ffffffff6115a716565b151561484982634000000063ffffffff6115a716565b15151415615045576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a51415614d88576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806148b757506001600160a01b038416600080516020615249833981519152145b806148de57506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b8061490057506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b15614afe5760408051633b3fb85360e21b81526001600160a01b0387811660048301526024820186905286166044820152905160009173abcc93c3be238884cc3309c19afd128fafc169119163ecfee14c916064808201928692909190829003018186803b15801561497157600080fd5b505afa158015614985573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260808110156149ae57600080fd5b815160208301805160405192949293830192919084600160201b8211156149d457600080fd5b9083019060208201858111156149e957600080fd5b8251600160201b811182820188101715614a0257600080fd5b82525081516020918201929091019080838360005b83811015614a2f578181015183820152602001614a17565b50505050905090810190601f168015614a5c5780820380516001836020036101000a031916815260200191505b506040818152918201516301e9a69560e41b82526001600160a01b038c16600483015260248201819052915191965073e2f2a5c287993345a840db3b0845fbc70f5935a59550631e9a695094506044808201945060209350908290030181600087803b158015614acb57600080fd5b505af1158015614adf573d6000803e3d6000fd5b505050506040513d6020811015614af557600080fd5b5061287c915050565b60408051633b3fb85360e21b81526001600160a01b0387166004820152602481018590526000805160206152498339815191526044820152905160009173abcc93c3be238884cc3309c19afd128fafc169119163ecfee14c916064808201928692909190829003018186803b158015614b7657600080fd5b505afa158015614b8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526080811015614bb357600080fd5b815160208301805160405192949293830192919084600160201b821115614bd957600080fd5b908301906020820185811115614bee57600080fd5b8251600160201b811182820188101715614c0757600080fd5b82525081516020918201929091019080838360005b83811015614c34578181015183820152602001614c1c565b50505050905090810190601f168015614c615780820380516001836020036101000a031916815260200191505b506040818152918201516301e9a69560e41b8252600080516020615249833981519152600483015260248201819052915191965073e2f2a5c287993345a840db3b0845fbc70f5935a59550631e9a695094506044808201945060209350908290030181600087803b158015614cd557600080fd5b505af1158015614ce9573d6000803e3d6000fd5b505050506040513d6020811015614cff57600080fd5b5050604080516370a0823160e01b81523060048201529051613fd59160008051602061524983398151915291889183916370a0823191602480820192602092909190829003018186803b158015614d5557600080fd5b505afa158015614d69573d6000803e3d6000fd5b505050506040513d6020811015614d7f57600080fd5b5051868661504e565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415615045576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481480614dee57506001600160a01b038516600080516020615249833981519152145b80614e1557506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b80614e3757506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b15614f0d57614e6a6001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff611fd816565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015614edb57600080fd5b505af1158015614eef573d6000803e3d6000fd5b505050506040513d6020811015614f0557600080fd5b5061287c9050565b614f288560008051602061524983398151915285858561504e565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160008051602061524983398151915291889183916370a08231916024808301926020929190829003018186803b158015614f9357600080fd5b505afa158015614fa7573d6000803e3d6000fd5b505050506040513d6020811015614fbd57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b15801561501b57600080fd5b505af115801561502f573d6000803e3d6000fd5b505050506040513d60208110156113e657600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561506d57611414565b6114148585858585600154615095906001600160a01b0387811691168563ffffffff611fd816565b6001546001600160a01b039081169063e2a7515e906150b5908816611499565b6150c05760006150c2565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561515a578181015183820152602001615142565b505050509050019750505050505050506020604051808303818588803b15801561518357600080fd5b505af1158015615197573d6000803e3d6000fd5b50505050506040513d60208110156151ae57600080fd5b50505050505050565b60405180604001604052806002906020820280388339509192915050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a723158206f45d82ac1efe97752bbcf64663dc8e548b807529aa81fbe1cb021ecb5106b5464736f6c63430005110032000000000000000000000000b97274ad8102cd447578338e66a529611c9609de00000000000000000000000087a79078dd5f904420ce5f77798b4ac635ed303c
Deployed Bytecode
0x6080604052600436106100705760003560e01c80638373f2651161004e5780638373f26514610436578063c7851396146104ed578063e2a7515e146106b0578063fbe4ed951461077857610070565b8063085e2c5b1461007f57806343ee21f0146101295780637b33701a1461015a575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b0381358116916020810135909116906040810135906060810135906080013561078d565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b34801561013557600080fd5b5061013e6107b0565b604080516001600160a01b039092168252519081900360200190f35b34801561016657600080fd5b50610396600480360360a081101561017d57600080fd5b810190602081018135600160201b81111561019757600080fd5b8201836020820111156101a957600080fd5b803590602001918460208302840111600160201b831117156101ca57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561022157600080fd5b82018360208201111561023357600080fd5b803590602001918460208302840111600160201b8311171561025457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460208302840111600160201b831117156102d657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561032557600080fd5b82018360208201111561033757600080fd5b803590602001918460208302840111600160201b8311171561035857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107bf945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b838110156103e05781810151838201526020016103c8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561041f578181015183820152602001610407565b505050509050019550505050505060405180910390f35b34801561044257600080fd5b5061048b600480360360c081101561045957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a20565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156104d75781810151838201526020016104bf565b5050505090500194505050505060405180910390f35b61069e600480360360a081101561050357600080fd5b810190602081018135600160201b81111561051d57600080fd5b82018360208201111561052f57600080fd5b803590602001918460208302840111600160201b8311171561055057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156105ab57600080fd5b8201836020820111156105bd57600080fd5b803590602001918460208302840111600160201b831117156105de57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561062d57600080fd5b82018360208201111561063f57600080fd5b803590602001918460208302840111600160201b8311171561066057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610b77945050505050565b60408051918252519081900360200190f35b61069e600480360360c08110156106c657600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561070557600080fd5b82018360208201111561071757600080fd5b803590602001918460208302840111600160201b8311171561073857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610dbd915050565b34801561078457600080fd5b5061013e610eb9565b600060606107a087878787876000610a20565b9199919850909650505050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156107f4578160200160208202803883390190505b50935060015b8951811015610a135789818151811061080f57fe5b60200260200101516001600160a01b03168a600183038151811061082f57fe5b60200260200101516001600160a01b0316141561088c578060011461086a5784600282038151811061085d57fe5b602002602001015161086c565b885b85600183038151811061087b57fe5b602002602001018181525050610a0b565b60608a905061092f8160018403815181106108a357fe5b60200260200101518284815181106108b757fe5b6020026020010151846001146108e3578860028603815181106108d657fe5b60200260200101516108e5565b8c5b8c60018703815181106108f457fe5b60200260200101518c600188038151811061090b57fe5b60200260200101518c600189038151811061092257fe5b6020026020010151610a20565b88600186038151811061093e57fe5b60209081029190910101929092529a509250610960858b63ffffffff610ec816565b945083516000141561099b578251604051908082528060200260200182016040528015610997578160200160208202803883390190505b5093505b60005b8451811015610a08576109e9600184036008028583815181106109bd57fe5b6020026020010151901b8683815181106109d357fe5b6020026020010151610ec890919063ffffffff16565b8582815181106109f557fe5b602090810291909101015260010161099e565b50505b6001016107fa565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610a9357600080fd5b505afa158015610aa7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610ad057600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610afa57600080fd5b908301906020820185811115610b0f57600080fd5b82518660208202830111600160201b82111715610b2b57600080fd5b82525081516020918201928201910280838360005b83811015610b58578181015183820152602001610b40565b5050505090500160405250505092509250925096509650969350505050565b6000610bad33308789600081518110610b8c57fe5b60200260200101516001600160a01b0316610f2b909392919063ffffffff16565b610bdd3087600081518110610bbe57fe5b60200260200101516001600160a01b031661104a90919063ffffffff16565b905060015b8651811015610d5e57868181518110610bf757fe5b60200260200101516001600160a01b0316876001830381518110610c1757fe5b60200260200101516001600160a01b03161415610c3357610d56565b60608451604051908082528060200260200182016040528015610c60578160200160208202803883390190505b50905060005b8551811015610cae5760018303600802868281518110610c8257fe5b6020026020010151901c60ff16828281518110610c9b57fe5b6020908102919091010152600101610c66565b50610cfb886001840381518110610cc157fe5b6020026020010151898481518110610cd557fe5b60200260200101518584886001880381518110610cee57fe5b60200260200101516110f4565b610d0b30898481518110610bbe57fe5b9250610d5333610d24308b6001870381518110610bbe57fe5b8a6001860381518110610d3357fe5b60200260200101516001600160a01b031661141b9092919063ffffffff16565b50505b600101610be2565b5083811015610d9e5760405162461bcd60e51b81526004018080602001828103825260358152602001806152146035913960400191505060405180910390fd5b610db333828860018a510381518110610d3357fe5b5095945050505050565b6000610dda6001600160a01b03881633308863ffffffff610f2b16565b6000610df56001600160a01b0389163063ffffffff61104a16565b9050610e0488888387876110f4565b610e1d6001600160a01b0388163063ffffffff61104a16565b915084821015610e5e5760405162461bcd60e51b81526004018080602001828103825260358152602001806152146035913960400191505060405180910390fd5b610e786001600160a01b038816338463ffffffff61141b16565b50610ead33610e966001600160a01b038b163063ffffffff61104a16565b6001600160a01b038b16919063ffffffff61141b16565b50509695505050505050565b6000546001600160a01b031681565b600082820183811015610f22576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b80610f3557611044565b610f3e84611499565b15611029576001600160a01b03831633148015610f5b5750803410155b610f965760405162461bcd60e51b815260040180806020018281038252602b815260200180615269602b913960400191505060405180910390fd5b6001600160a01b0382163014610fde576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fdc573d6000803e3d6000fd5b505b8034111561102457336108fc610ffa348463ffffffff6114d516565b6040518115909202916000818181858888f19350505050158015611022573d6000803e3d6000fd5b505b611044565b6110446001600160a01b03851684848463ffffffff61151716565b50505050565b600061105583611499565b1561106b57506001600160a01b03811631610f25565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110c157600080fd5b505afa1580156110d5573d6000803e3d6000fd5b505050506040513d60208110156110eb57600080fd5b50519050610f25565b61110d6001600160a01b0386168563ffffffff61157116565b1561111757611414565b61112b81600160431b63ffffffff6115a716565b6114075760408051635b16ebb760e01b81526001600160a01b0387166004820152905160009173c12a7e093832e2d2267df225baca60bd2b74c65f91635b16ebb791602480820192602092909190829003018186803b15801561118d57600080fd5b505afa1580156111a1573d6000803e3d6000fd5b505050506040513d60208110156111b757600080fd5b505160408051635b16ebb760e01b81526001600160a01b0388166004820152905191925060009173c12a7e093832e2d2267df225baca60bd2b74c65f91635b16ebb7916024808301926020929190829003018186803b15801561121957600080fd5b505afa15801561122d573d6000803e3d6000fd5b505050506040513d602081101561124357600080fd5b505190508180156112515750805b156113cf5760608451604051908082528060200260200182016040528015611283578160200160208202803883390190505b50905060005b85518110156112d75785818151811061129e57fe5b60200260200101516fffffffffffffffffffffffffffffffff168282815181106112c457fe5b6020908102919091010152600101611289565b5060006112fe73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3063ffffffff61104a16565b90506113258973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8985600160431b6115ad565b60005b865181101561136857608087828151811061133f57fe5b6020026020010151901c83828151811061135557fe5b6020908102919091010152600101611328565b50600061138f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3063ffffffff61104a16565b90506113c573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8a6113ba848663ffffffff6114d516565b86600160431b611872565b5050505050611414565b81156113ed576113e687878787600160431b6115ad565b5050611414565b8015611404576113e687878787600160431b611872565b50505b6114148585858585611ce3565b5050505050565b60008161142a57506001611492565b61143384611499565b15611474576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561146e573d6000803e3d6000fd5b50611492565b61148e6001600160a01b038516848463ffffffff611cf016565b5060015b9392505050565b60006001600160a01b03821615806114cd57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b6000610f2283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d47565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611044908590611dde565b6000816001600160a01b0316836001600160a01b03161480610f22575061159783611499565b8015610f225750610f2282611499565b16151590565b6115b56151b7565b604080518082018083526327b2595f60e11b905260006044820152905181906001600160a01b03891690634f64b2be90606480850191602091818703018186803b15801561160257600080fd5b505afa158015611616573d6000803e3d6000fd5b505050506040513d602081101561162c57600080fd5b50516001600160a01b039081168252604080516327b2595f60e11b8152600160048201529051602093840193928b1692634f64b2be9260248082019391829003018186803b15801561167d57600080fd5b505afa158015611691573d6000803e3d6000fd5b505050506040513d60208110156116a757600080fd5b50516001600160a01b039081169091526040805160008082526020808301808552632c8aec0360e11b8152602484018b815260448501958652845160648601819052979850958d1696635915d806968c969094909360848701939202908190849084905b8381101561172357818101518382015260200161170b565b505050509050019350505050600060405180830381600087803b15801561174957600080fd5b505af115801561175d573d6000803e3d6000fd5b505050506060835160405190808252806020026020018201604052801561178e578160200160208202803883390190505b50905060005b6002811015611868576117c78382600281106117ac57fe5b60200201516001600160a01b0389169063ffffffff61157116565b156117d157611860565b60005b855181101561181957816008028682815181106117ed57fe5b6020026020010151901c60ff1683828151811061180657fe5b60209081029190910101526001016117d4565b5061186083826002811061182957fe5b6020020151886118593087866002811061183f57fe5b60200201516001600160a01b03169063ffffffff61104a16565b8588611ce3565b600101611794565b5050505050505050565b61187a6151b7565b604080518082018083526327b2595f60e11b905260006044820152905181906001600160a01b03881690634f64b2be90606480850191602091818703018186803b1580156118c757600080fd5b505afa1580156118db573d6000803e3d6000fd5b505050506040513d60208110156118f157600080fd5b50516001600160a01b039081168252604080516327b2595f60e11b8152600160048201529051602093840193928a1692634f64b2be9260248082019391829003018186803b15801561194257600080fd5b505afa158015611956573d6000803e3d6000fd5b505050506040513d602081101561196c57600080fd5b50516001600160a01b031690526040805160028082526060808301845293945090916020830190803883390190505090506119ae85600263ffffffff611f9616565b816000815181106119bb57fe5b6020026020010181815250506119ee816000815181106119d757fe5b6020026020010151866114d590919063ffffffff16565b816001815181106119fb57fe5b60200260200101818152505060608451604051908082528060200260200182016040528015611a34578160200160208202803883390190505b50905060005b6002811015611b5f57611a6d848260028110611a5257fe5b60200201516001600160a01b038b169063ffffffff61157116565b15611a7757611b57565b60005b8651811015611abf5781600802878281518110611a9357fe5b6020026020010151901c60ff16838281518110611aac57fe5b6020908102919091010152600101611a7a565b50611af089858360028110611ad057fe5b6020020151858481518110611ae157fe5b60200260200101518589611ce3565b611b003085836002811061183f57fe5b838281518110611b0c57fe5b602002602001018181525050611b5788848381518110611b2857fe5b6020026020010151868460028110611b3c57fe5b60200201516001600160a01b0316919063ffffffff611fd816565b600101611a3a565b506000611b7c8460015b60200201516001600160a01b0316611499565b611b87576000611b9d565b82600181518110611b9457fe5b60200260200101515b611ba8856000611b69565b611bb3576000611bc9565b83600081518110611bc057fe5b60200260200101515b019050876001600160a01b0316635dc55f2f828560006040518463ffffffff1660e01b81526004018080602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015611c34578181015183820152602001611c1c565b5050505090500193505050506020604051808303818588803b158015611c5957600080fd5b505af1158015611c6d573d6000803e3d6000fd5b50505050506040513d6020811015611c8457600080fd5b50600090505b6002811015611cd757611cce33611ca73088856002811061183f57fe5b878460028110611cb357fe5b60200201516001600160a01b0316919063ffffffff61141b16565b50600101611c8a565b50505050505050505050565b61141485858585856120cc565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d42908490611dde565b505050565b60008184841115611dd65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611d9b578181015183820152602001611d83565b50505050905090810190601f168015611dc85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b611df0826001600160a01b031661241a565b611e41576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310611e7f5780518252601f199092019160209182019101611e60565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ee1576040519150601f19603f3d011682016040523d82523d6000602084013e611ee6565b606091505b509150915081611f3d576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561104457808060200190516020811015611f5957600080fd5b50516110445760405162461bcd60e51b815260040180806020018281038252602a815260200180615294602a913960400191505060405180910390fd5b6000610f2283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612456565b611fe183611499565b611d42578061200a576120056001600160a01b03841683600063ffffffff6124bb16565b611d42565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d602081101561208557600080fd5b50519050818110156110445780156120b2576120b26001600160a01b03851684600063ffffffff6124bb16565b6110446001600160a01b038516848463ffffffff6124bb16565b836001600160a01b0316856001600160a01b031614156120eb57611414565b612101816508000000000063ffffffff6115a716565b151561211782634000000063ffffffff6115a716565b1515141561240d57600061212a866125ce565b90506001600160a01b03808216146122b257856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561218257600080fd5b505af1158015612196573d6000803e3d6000fd5b505050506040513d60208110156121ac57600080fd5b50600090506121ca6001600160a01b0383163063ffffffff61104a16565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156122645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561224b57600080fd5b505af115801561225f573d6000803e3d6000fd5b505050505b6122b06001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21461229157826122a7565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b878387876120cc565b505b6122bb856125ce565b90506001600160a01b038082161461240b57612319866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146122fb5782612311565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686612702565b6000612374306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214612349578361235f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff61104a16565b90505b6123916001600160a01b038316878363ffffffff611fd816565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156123d757600080fd5b505af11580156123eb573d6000803e3d6000fd5b505050506040513d602081101561240157600080fd5b5061141492505050565b505b6114148585858585612702565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061244e57508115155b949350505050565b600081836124a55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611d9b578181015183820152602001611d83565b5060008385816124b157fe5b0495945050505050565b801580612541575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561251357600080fd5b505afa158015612527573d6000803e3d6000fd5b505050506040513d602081101561253d57600080fd5b5051155b61257c5760405162461bcd60e51b81526004018080602001828103825260368152602001806152be6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052611d42908490611dde565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b6020831061265c5780518252601f19909201916020918201910161263d565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126bc576040519150601f19603f3d011682016040523d82523d6000602084013e6126c1565b606091505b50915091508115806126d257508051155b156126e357600019925050506114d0565b8080602001905160208110156126f857600080fd5b5051949350505050565b61141485858585855b836001600160a01b0316856001600160a01b0316141561272a57611414565b61273d816208000063ffffffff6115a716565b151561275382634000000063ffffffff6115a716565b15151415612a3d576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2141561288157604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156127d957600080fd5b505afa1580156127ed573d6000803e3d6000fd5b505050506040513d602081101561280357600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561284357600080fd5b505af1158015612857573d6000803e3d6000fd5b5050505061287c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585612a46565b611414565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce31514156128ff57604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156127d957600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156129a8576129458573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858561270b565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561299457600080fd5b505af11580156113c5573d6000803e3d6000fd5b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415612a3d576129ee8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858561270b565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b15801561299457600080fd5b61141485858585855b61141485858585855b612a62816280000063ffffffff6115a716565b15612a7782634000000063ffffffff6115a716565b151415612ec957612a866151d5565b612a8e612ed6565b905060005b6008811015612c6157818160088110612aa857fe5b60200201516001600160a01b0316876001600160a01b03161415612c59576000828260088110612ad457fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b1157600080fd5b505afa158015612b25573d6000803e3d6000fd5b505050506040513d6020811015612b3b57600080fd5b505190506000838360088110612b4d57fe5b60200201516001600160a01b031663c85c93aa8860016000604051908082528060200260200182016040528015612b8e578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015612bee578181015183820152602001612bd6565b50505050905001945050505050602060405180830381600087803b158015612c1557600080fd5b505af1158015612c29573d6000803e3d6000fd5b505050506040513d6020811015612c3f57600080fd5b50519050612c508289838989612a4f565b50505050611414565b600101612a93565b5060005b6008811015612ec657818160088110612c7a57fe5b60200201516001600160a01b0316866001600160a01b03161415612ebe576000828260088110612ca657fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ce357600080fd5b505afa158015612cf7573d6000803e3d6000fd5b505050506040513d6020811015612d0d57600080fd5b50519050612d1e8882888888612fbc565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b158015612d6857600080fd5b505afa158015612d7c573d6000803e3d6000fd5b505050506040513d6020811015612d9257600080fd5b50519050612dc1848460088110612da557fe5b60200201516001600160a01b038416908363ffffffff611fd816565b838360088110612dcd57fe5b60200201516001600160a01b0316633cfcef64826000604051908082528060200260200182016040528015612e0c578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015612e62578181015183820152602001612e4a565b505050509050019350505050602060405180830381600087803b158015612e8857600080fd5b505af1158015612e9c573d6000803e3d6000fd5b505050506040513d6020811015612eb257600080fd5b50611414945050505050565b600101612c65565b50505b6114148585858585612fbc565b612ede6151d5565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b61141485858585855b836001600160a01b0316856001600160a01b03161415612fe457611414565b612ff68161080063ffffffff6115a716565b151561300c82634000000063ffffffff6115a716565b151514156133a75761301c6151f4565b6130246133b4565b905060005b600d8110156131e1578181600d811061303e57fe5b60200201516001600160a01b0316876001600160a01b031614156131d95760008282600d811061306a57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156130a757600080fd5b505afa1580156130bb573d6000803e3d6000fd5b505050506040513d60208110156130d157600080fd5b505190508282600d81106130e157fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561312b57600080fd5b505af115801561313f573d6000803e3d6000fd5b505050506131d18188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561319e57600080fd5b505afa1580156131b2573d6000803e3d6000fd5b505050506040513d60208110156131c857600080fd5b50518888612fc5565b505050611414565b600101613029565b5060005b600d8110156133a4578181600d81106131fa57fe5b60200201516001600160a01b0316866001600160a01b0316141561339c5760008282600d811061322657fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561326357600080fd5b505afa158015613277573d6000803e3d6000fd5b505050506040513d602081101561328d57600080fd5b5051905061329e8882888888613521565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156132e857600080fd5b505afa1580156132fc573d6000803e3d6000fd5b505050506040513d602081101561331257600080fd5b505190506133258484600d8110612da557fe5b8383600d811061333157fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561337b57600080fd5b505af115801561338f573d6000803e3d6000fd5b5050505050505050611414565b6001016131e5565b50505b6114148585858585613521565b6133bc6151f4565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b61141485858585855b836001600160a01b0316856001600160a01b0316141561354957611414565b61355a81601063ffffffff6115a716565b151561357082634000000063ffffffff6115a716565b151514156137f75760408051639bbde94760e01b81526001600160a01b0387166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b1580156135d657600080fd5b505afa1580156135ea573d6000803e3d6000fd5b505050506040513d602081101561360057600080fd5b505190506001600160a01b038116156136b057856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561365957600080fd5b505af115801561366d573d6000803e3d6000fd5b505050506040513d602081101561368357600080fd5b50600090506136a16001600160a01b0383163063ffffffff61104a16565b90506113e6828783878761352a565b60408051639bbde94760e01b81526001600160a01b0387166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b15801561370a57600080fd5b505afa15801561371e573d6000803e3d6000fd5b505050506040513d602081101561373457600080fd5b505190506001600160a01b038116156137f5576137548682868686613800565b600061376f6001600160a01b0383163063ffffffff61104a16565b9050613783826001600160a01b0316611499565b1561237757734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156137d757600080fd5b505af11580156137eb573d6000803e3d6000fd5b50505050506113e6565b505b61141485858585855b6114148585858585836001600160a01b0316856001600160a01b0316141561382757611414565b61383881602063ffffffff6115a716565b151561384e82634000000063ffffffff6115a716565b15151415613af557600061386186613b02565b90506001600160a01b03808216146139b157613885816001600160a01b0316611499565b1561390b576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b1580156138d957600080fd5b505af11580156138ed573d6000803e3d6000fd5b505050506040513d602081101561390357600080fd5b506139879050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b15801561395a57600080fd5b505af115801561396e573d6000803e3d6000fd5b505050506040513d602081101561398457600080fd5b50505b60006139a26001600160a01b0383163063ffffffff61104a16565b90506113e68287838787613e78565b6139ba85613b02565b90506001600160a01b0380821614613af3576139d98682868686613e78565b60006139f46001600160a01b0383163063ffffffff61104a16565b9050613a08826001600160a01b0316611499565b15613a8a5760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b158015613a5757600080fd5b505af1158015613a6b573d6000803e3d6000fd5b50505050506040513d6020811015613a8257600080fd5b506113e69050565b613aa46001600160a01b038316878363ffffffff611fd816565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b1580156123d757600080fd5b505b6114148585858585613e78565b6000613b16826001600160a01b0316611499565b15613b2457506000196114d0565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b60208310613b8f5780518252601f199092019160209182019101613b70565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613bf0576040519150601f19603f3d011682016040523d82523d6000602084013e613bf5565b606091505b509150915081613c0b57600019925050506114d0565b6000805b8251816006011015613d6457828160000181518110613c2a57fe5b6020910101516001600160f81b031916602360f91b148015613c6d5750828160010181518110613c5657fe5b6020910101516001600160f81b031916607560f81b145b8015613c9a5750828160020181518110613c8357fe5b6020910101516001600160f81b031916601b60fa1b145b8015613cc75750828160030181518110613cb057fe5b6020910101516001600160f81b031916606360f81b145b8015613cf45750828160040181518110613cdd57fe5b6020910101516001600160f81b031916603960f91b145b8015613d215750828160050181518110613d0a57fe5b6020910101516001600160f81b031916607560f81b145b8015613d4e5750828160060181518110613d3757fe5b6020910101516001600160f81b031916606d60f81b145b15613d5c5760019150613d64565b600101613c0f565b5080613d775760001993505050506114d0565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b60208310613dda5780518252601f199092019160209182019101613dbb565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613e3b576040519150601f19603f3d011682016040523d82523d6000602084013e613e40565b606091505b50909350915082613e585760001993505050506114d0565b818060200190516020811015613e6d57600080fd5b505195945050505050565b61141485858585855b836001600160a01b0316856001600160a01b03161415613ea057611414565b613eb181608063ffffffff6115a716565b1515613ec782634000000063ffffffff6115a716565b1515141561421157604080516354732ba160e11b81526001600160a01b0387166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b158015613f2d57600080fd5b505afa158015613f41573d6000803e3d6000fd5b505050506040513d6020811015613f5757600080fd5b505190506001600160a01b03811615613fdb57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613fb057600080fd5b505af1158015613fc4573d6000803e3d6000fd5b50505050613fd58186868686613e81565b50611414565b604080516354732ba160e11b81526001600160a01b0387166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b15801561403557600080fd5b505afa158015614049573d6000803e3d6000fd5b505050506040513d602081101561405f57600080fd5b505190506001600160a01b0381161561420f5761407f868286868661421a565b600061409a6001600160a01b0383163063ffffffff61104a16565b905061412f73398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ec57600080fd5b505afa158015614100573d6000803e3d6000fd5b505050506040513d602081101561411657600080fd5b50516001600160a01b038416908363ffffffff611fd816565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e06661415b6001600160a01b038516611499565b614166576000614168565b825b61417a856001600160a01b0316611499565b614184578461419a565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b1580156141ef57600080fd5b505af1158015614203573d6000803e3d6000fd5b50505050505050611414565b505b61141485858585855b836001600160a01b0316856001600160a01b0316141561423957611414565b61424b8161040063ffffffff6115a716565b151561426182634000000063ffffffff6115a716565b15151415614538576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e814156143ee57736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156142e857600080fd5b505af11580156142fc573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b15801561435557600080fd5b505afa158015614369573d6000803e3d6000fd5b505050506040513d602081101561437f57600080fd5b5051905080156143d35760606143ad73b683d83a532e2cb7dfa5275eed3698436371cc9f878460018761078d565b9150506143d173b683d83a532e2cb7dfa5275eed3698436371cc9f878484876110f4565b505b613fd560008051602061524983398151915286868686614541565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e814156145385761442e85600080516020615249833981519152858585614541565b604080516370a0823160e01b81523060048201529051600091600080516020615249833981519152916370a0823191602480820192602092909190829003018186803b15801561447d57600080fd5b505afa158015614491573d6000803e3d6000fd5b505050506040513d60208110156144a757600080fd5b505190506144de600080516020615249833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff611fd816565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561299457600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561456057611414565b61457181604063ffffffff6115a716565b151561458782634000000063ffffffff6115a716565b151514156147f5576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c21514156146ac576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b15801561460d57600080fd5b505af1158015614621573d6000803e3d6000fd5b5050604080516370a0823160e01b8152306004820152905161287c93506000805160206152498339815191529250879183916370a0823191602480820192602092909190829003018186803b15801561467957600080fd5b505afa15801561468d573d6000803e3d6000fd5b505050506040513d60208110156146a357600080fd5b505185856147fe565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c21514156147f5576146ec856000805160206152498339815191528585856147fe565b604080516370a0823160e01b81523060048201529051600091600080516020615249833981519152916370a0823191602480820192602092909190829003018186803b15801561473b57600080fd5b505afa15801561474f573d6000803e3d6000fd5b505050506040513d602081101561476557600080fd5b5051905061479c6000805160206152498339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff611fd816565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b15801561299457600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561481d57611414565b614833816502000000000063ffffffff6115a716565b151561484982634000000063ffffffff6115a716565b15151415615045576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a51415614d88576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806148b757506001600160a01b038416600080516020615249833981519152145b806148de57506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b8061490057506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b15614afe5760408051633b3fb85360e21b81526001600160a01b0387811660048301526024820186905286166044820152905160009173abcc93c3be238884cc3309c19afd128fafc169119163ecfee14c916064808201928692909190829003018186803b15801561497157600080fd5b505afa158015614985573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260808110156149ae57600080fd5b815160208301805160405192949293830192919084600160201b8211156149d457600080fd5b9083019060208201858111156149e957600080fd5b8251600160201b811182820188101715614a0257600080fd5b82525081516020918201929091019080838360005b83811015614a2f578181015183820152602001614a17565b50505050905090810190601f168015614a5c5780820380516001836020036101000a031916815260200191505b506040818152918201516301e9a69560e41b82526001600160a01b038c16600483015260248201819052915191965073e2f2a5c287993345a840db3b0845fbc70f5935a59550631e9a695094506044808201945060209350908290030181600087803b158015614acb57600080fd5b505af1158015614adf573d6000803e3d6000fd5b505050506040513d6020811015614af557600080fd5b5061287c915050565b60408051633b3fb85360e21b81526001600160a01b0387166004820152602481018590526000805160206152498339815191526044820152905160009173abcc93c3be238884cc3309c19afd128fafc169119163ecfee14c916064808201928692909190829003018186803b158015614b7657600080fd5b505afa158015614b8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526080811015614bb357600080fd5b815160208301805160405192949293830192919084600160201b821115614bd957600080fd5b908301906020820185811115614bee57600080fd5b8251600160201b811182820188101715614c0757600080fd5b82525081516020918201929091019080838360005b83811015614c34578181015183820152602001614c1c565b50505050905090810190601f168015614c615780820380516001836020036101000a031916815260200191505b506040818152918201516301e9a69560e41b8252600080516020615249833981519152600483015260248201819052915191965073e2f2a5c287993345a840db3b0845fbc70f5935a59550631e9a695094506044808201945060209350908290030181600087803b158015614cd557600080fd5b505af1158015614ce9573d6000803e3d6000fd5b505050506040513d6020811015614cff57600080fd5b5050604080516370a0823160e01b81523060048201529051613fd59160008051602061524983398151915291889183916370a0823191602480820192602092909190829003018186803b158015614d5557600080fd5b505afa158015614d69573d6000803e3d6000fd5b505050506040513d6020811015614d7f57600080fd5b5051868661504e565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415615045576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481480614dee57506001600160a01b038516600080516020615249833981519152145b80614e1557506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b80614e3757506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b15614f0d57614e6a6001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff611fd816565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015614edb57600080fd5b505af1158015614eef573d6000803e3d6000fd5b505050506040513d6020811015614f0557600080fd5b5061287c9050565b614f288560008051602061524983398151915285858561504e565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160008051602061524983398151915291889183916370a08231916024808301926020929190829003018186803b158015614f9357600080fd5b505afa158015614fa7573d6000803e3d6000fd5b505050506040513d6020811015614fbd57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b15801561501b57600080fd5b505af115801561502f573d6000803e3d6000fd5b505050506040513d60208110156113e657600080fd5b61141485858585855b836001600160a01b0316856001600160a01b0316141561506d57611414565b6114148585858585600154615095906001600160a01b0387811691168563ffffffff611fd816565b6001546001600160a01b039081169063e2a7515e906150b5908816611499565b6150c05760006150c2565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b8381101561515a578181015183820152602001615142565b505050509050019750505050505050506020604051808303818588803b15801561518357600080fd5b505af1158015615197573d6000803e3d6000fd5b50505050506040513d60208110156151ae57600080fd5b50505050505050565b60405180604001604052806002906020820280388339509192915050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a723158206f45d82ac1efe97752bbcf64663dc8e548b807529aa81fbe1cb021ecb5106b5464736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b97274ad8102cd447578338e66a529611c9609de00000000000000000000000087a79078dd5f904420ce5f77798b4ac635ed303c
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0xb97274AD8102cD447578338E66a529611C9609DE
Arg [1] : _oneSplit (address): 0x87a79078dd5f904420ce5f77798B4ac635ed303c
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b97274ad8102cd447578338e66a529611c9609de
Arg [1] : 00000000000000000000000087a79078dd5f904420ce5f77798b4ac635ed303c
Deployed Bytecode Sourcemap
224904:5955:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;225523:10;225537:9;225523:23;;225515:32;;;;;;224904:5955;225563:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;225563:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;225563: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;225563:515:0;;;;;;;;;;;;;;;;;;225228:25;;8:9:-1;5:2;;;30:1;27;20:12;5:2;225228:25:0;;;:::i;:::-;;;;-1:-1:-1;;;;;225228:25:0;;;;;;;;;;;;;;226721:1551;;8:9:-1;5:2;;;30:1;27;20:12;5:2;226721:1551:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;226721:1551:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;226721:1551:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;226721:1551: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;226721:1551:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;226721:1551:0;;;;;;;;;-1:-1:-1;226721:1551:0;;;;-1:-1:-1;226721:1551:0;;;;-1:-1:-1;;;;5:28;;2:2;;;46:1;43;36:12;2:2;226721:1551:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;226721:1551: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;226721:1551:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;226721:1551:0;;;;;;;;-1:-1:-1;226721:1551:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;226721:1551:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;226721:1551: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;226721:1551:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;226721:1551:0;;;;;;;;-1:-1:-1;226721:1551:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;226721:1551:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;226721:1551: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;226721:1551:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;226721:1551:0;;-1:-1:-1;226721:1551:0;;-1:-1:-1;;;;;226721:1551: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;226721:1551: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;226721:1551:0;;;;;;;;;;;;;;;;;;;;226086:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;226086:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;226086: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;226086:627:0;;;;;;;;;;;;;;;;;;;229086:1306;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;229086:1306:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;229086:1306:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;229086:1306: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;229086:1306:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;229086:1306:0;;;;;;;;;;;;-1:-1:-1;229086:1306:0;-1:-1:-1;229086:1306:0;;;;-1:-1:-1;229086:1306:0;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;229086:1306:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;229086:1306: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;229086:1306:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;229086:1306:0;;;;;;;;-1:-1:-1;229086:1306:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;229086:1306:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;229086:1306: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;229086:1306:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;229086:1306:0;;-1:-1:-1;229086:1306:0;;-1:-1:-1;;;;;229086:1306:0:i;:::-;;;;;;;;;;;;;;;;228280:798;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;228280:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;228280:798:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;228280: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;228280:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;228280:798:0;;-1:-1:-1;;228280:798:0;;;-1:-1:-1;228280:798:0;;-1:-1:-1;;228280:798:0:i;225188:33::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;225188:33:0;;;:::i;225563:515::-;225785:20;225820:29;225910:160;225949:9;225973;225997:6;226018:5;226038;226058:1;225910:24;:160::i;:::-;225877:193;;;;-1:-1:-1;225563:515:0;;-1:-1:-1;;;;;;;225563:515:0:o;225228:25::-;;;-1:-1:-1;;;;;225228:25:0;;:::o;226721:1551::-;227011:30;227056:25;227096:29;227153:21;227233:1;227217:6;:13;:17;227203:32;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;227203:32:0;-1:-1:-1;227187:48:0;-1:-1:-1;227260:1:0;227246:1019;227267:6;:13;227263:1;:17;227246:1019;;;227323:6;227330:1;227323:9;;;;;;;;;;;;;;-1:-1:-1;;;;;227306:26:0;:6;227317:1;227313;:5;227306:13;;;;;;;;;;;;;;-1:-1:-1;;;;;227306:26:0;;227302:157;;;227377:1;227382;227377:6;227376:40;;227396:13;227414:1;227410;:5;227396:20;;;;;;;;;;;;;;227376:40;;;227387:6;227376:40;227353:13;227371:1;227367;:5;227353:20;;;;;;;;;;;;;:63;;;;;227435:8;;227302:157;227475:23;227501:6;227475:32;;227629:279;227672:7;227684:1;227680;:5;227672:14;;;;;;;;;;;;;;227705:7;227713:1;227705:10;;;;;;;;;;;;;;227735:1;227740;227735:6;227734:40;;227754:13;227772:1;227768;:5;227754:20;;;;;;;;;;;;;;227734:40;;;227745:6;227734:40;227793:5;227803:1;227799;:5;227793:12;;;;;;;;;;;;;;227824:5;227834:1;227830;:5;227824:12;;;;;;;;;;;;;;227855:31;227891:1;227887;:5;227855:38;;;;;;;;;;;;;;227629:24;:279::i;:::-;227543:13;227561:1;227557;:5;227543:20;;;;;;;;;;;;;;;;;227524:384;;;;;-1:-1:-1;227524:384:0;-1:-1:-1;227943:29:0;:17;227524:384;227943:29;:21;:29;:::i;:::-;227923:49;;227993:12;:19;228016:1;227993:24;227989:106;;;228067:4;:11;228053:26;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;228053:26:0;;228038:41;;227989:106;228114:6;228109:145;228130:12;:19;228126:1;:23;228109:145;;;228193:45;228234:1;228230;:5;228225:1;:11;228213:4;228218:1;228213:7;;;;;;;;;;;;;;:24;;228193:12;228206:1;228193:15;;;;;;;;;;;;;;:19;;:45;;;;:::i;:::-;228175:12;228188:1;228175:15;;;;;;;;;;;;;;;;;:63;228151:3;;228109:145;;;;227246:1019;;227282:3;;227246:1019;;;;226721:1551;;;;;;;;;;:::o;226086:627::-;226364:20;226503:12;;:202;;;-1:-1:-1;;;226503:202:0;;-1:-1:-1;;;;;226503:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;226364:20;;226439:29;;226503:12;;:37;;:202;;;;;226364:20;;226503:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;226503:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;226503:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;226503: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;226503: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;226503:202:0;;421:4:-1;412:14;;;;226503:202:0;;;;;412:14:-1;226503: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;226503:202:0;;;;;;;;;;;226496:209;;;;;;226086:627;;;;;;;;;;:::o;229086:1306::-;229294:20;229327:66;229359:10;229379:4;229386:6;229327;229334:1;229327:9;;;;;;;;;;;;;;-1:-1:-1;;;;;229327:31:0;;;:66;;;;;;:::i;:::-;229421:43;229458:4;229421:6;229428:1;229421:9;;;;;;;;;;;;;;-1:-1:-1;;;;;229421:28:0;;;:43;;;;:::i;:::-;229406:58;-1:-1:-1;229489:1:0;229475:726;229496:6;:13;229492:1;:17;229475:726;;;229552:6;229559:1;229552:9;;;;;;;;;;;;;;-1:-1:-1;;;;;229535:26:0;:6;229546:1;229542;:5;229535:13;;;;;;;;;;;;;;-1:-1:-1;;;;;229535:26:0;;229531:75;;;229582:8;;229531:75;229622:21;229660:12;:19;229646:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;229646:34:0;-1:-1:-1;229622:58:0;-1:-1:-1;229700:6:0;229695:133;229716:12;:19;229712:1;:23;229695:133;;;229801:1;229797;:5;229792:1;:11;229772:12;229785:1;229772:15;;;;;;;;;;;;;;:32;;229808:4;229771:41;229761:4;229766:1;229761:7;;;;;;;;;;;;;;;;;:51;229737:3;;229695:133;;;;229844:165;229868:6;229879:1;229875;:5;229868:13;;;;;;;;;;;;;;229900:6;229907:1;229900:9;;;;;;;;;;;;;;229928:12;229959:4;229982:5;229992:1;229988;:5;229982:12;;;;;;;;;;;;;;229844:5;:165::i;:::-;230039:43;230076:4;230039:6;230046:1;230039:9;;;;;;;:43;230024:58;;230097:92;230129:10;230141:47;230182:4;230141:6;230152:1;230148;:5;230141:13;;;;;;;:47;230097:6;230108:1;230104;:5;230097:13;;;;;;;;;;;;;;-1:-1:-1;;;;;230097:31:0;;;:92;;;;;:::i;:::-;;229475:726;;229511:3;;229475:726;;;;230237:9;230221:12;:25;;230213:91;;;;-1:-1:-1;;;230213:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;230315:69;230359:10;230371:12;230315:6;230338:1;230322:6;:13;:17;230315:25;;;;;;;:69;;229086:1306;;;;;;;:::o;228280:798::-;228495:20;228528:66;-1:-1:-1;;;;;228528:31:0;;228560:10;228580:4;228587:6;228528:66;:31;:66;:::i;:::-;228605:17;228625:43;-1:-1:-1;;;;;228625:28:0;;228662:4;228625:43;:28;:43;:::i;:::-;228605:63;;228679:59;228685:9;228696;228707;228718:12;228732:5;228679;:59::i;:::-;228766:43;-1:-1:-1;;;;;228766:28:0;;228803:4;228766:43;:28;:43;:::i;:::-;228751:58;;228844:9;228828:12;:25;;228820:91;;;;-1:-1:-1;;;228820:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;228922:53;-1:-1:-1;;;;;228922:27:0;;228950:10;228962:12;228922:53;:27;:53;:::i;:::-;-1:-1:-1;228986:84:0;229014:10;229026:43;-1:-1:-1;;;;;229026:28:0;;229063:4;229026:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;228986:27:0;;;:84;;:27;:84;:::i;:::-;;228280:798;;;;;;;;;:::o;225188:33::-;;;-1:-1:-1;;;;;225188:33:0;;:::o;12663:181::-;12721:7;12753:5;;;12777:6;;;;12769:46;;;;;-1:-1:-1;;;12769:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;12835:1;-1:-1:-1;12663:181:0;;;;;:::o;39201:617::-;39312:11;39308:50;;39340:7;;39308:50;39374:12;39380:5;39374;:12::i;:::-;39370:441;;;-1:-1:-1;;;;;39411:18:0;;39419:10;39411:18;:41;;;;;39446:6;39433:9;:19;;39411:41;39403:97;;;;-1:-1:-1;;;39403:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;39519:19:0;;39533:4;39519:19;39515:97;;39559:37;;-1:-1:-1;;;;;39559:29:0;;;:37;;;;;39589:6;;39559:37;;;;39589:6;39559:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39559:37:0;39515:97;39642:6;39630:9;:18;39626:101;;;39669:10;:42;39689:21;:9;39703:6;39689:21;:13;:21;:::i;:::-;39669:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39669:42:0;39626:101;39370:441;;;39759:40;-1:-1:-1;;;;;39759:22:0;;39782:4;39788:2;39792:6;39759:40;:22;:40;:::i;:::-;39201:617;;;;:::o;40803:228::-;40881:7;40905:12;40911:5;40905;:12::i;:::-;40901:123;;;-1:-1:-1;;;;;;40941:11:0;;;40934:18;;40901:123;40992:5;-1:-1:-1;;;;;40992:15:0;;41008:3;40992:20;;;;;;;;;;;;;-1:-1:-1;;;;;40992:20:0;-1:-1:-1;;;;;40992:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;40992:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;40992:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;40992:20:0;;-1:-1:-1;40985:27:0;;217318:2387;217505:21;-1:-1:-1;;;;;217505:12:0;;217518:7;217505:21;:12;:21;:::i;:::-;217501:60;;;217543:7;;217501:60;217578:46;:5;-1:-1:-1;;;217578:46:0;:11;:46;:::i;:::-;217573:1969;;217664:44;;;-1:-1:-1;;;217664:44:0;;-1:-1:-1;;;;;217664:44:0;;;;;;;;217641:20;;74032:42;;217664:24;;:44;;;;;;;;;;;;;;;74032:42;217664:44;;;5:2:-1;;;;30:1;27;20:12;5:2;217664:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;217664:44:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;217664:44:0;217744:42;;;-1:-1:-1;;;217744:42:0;;-1:-1:-1;;;;;217744:42:0;;;;;;;;217664:44;;-1:-1:-1;217723:18:0;;74032:42;;217744:24;;:42;;;;;217664:44;;217744:42;;;;;;;74032;217744;;;5:2:-1;;;;30:1;27;20:12;5:2;217744:42:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;217744:42:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;217744:42:0;;-1:-1:-1;217807:15:0;:32;;;;;217826:13;217807:32;217803:1126;;;217860:21;217898:12;:19;217884:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;217884:34:0;-1:-1:-1;217860:58:0;-1:-1:-1;217942:6:0;217937:134;217958:12;:19;217954:1;:23;217937:134;;;218017:12;218030:1;218017:15;;;;;;;;;;;;;;218036:14;218017:34;218007:4;218012:1;218007:7;;;;;;;;;;;;;;;;;:44;217979:3;;217937:134;;;-1:-1:-1;218091:24:0;218118:45;70089:42;218157:4;218118:45;:30;:45;:::i;:::-;218091:72;;218184:220;218230:9;70089:42;218296:6;218325:4;-1:-1:-1;;;218184:23:0;:220::i;:::-;218430:6;218425:122;218446:12;:19;218442:1;:23;218425:122;;;218524:3;218505:12;218518:1;218505:15;;;;;;;;;;;;;;:22;;218495:4;218500:1;218495:7;;;;;;;;;;;;;;;;;:32;218467:3;;218425:122;;;-1:-1:-1;218567:23:0;218593:45;70089:42;218632:4;218593:45;:30;:45;:::i;:::-;218567:71;-1:-1:-1;218666:247:0;70089:42;218744:7;218774:37;218567:71;218794:16;218774:37;:19;:37;:::i;:::-;218834:4;-1:-1:-1;;;218666:21:0;:247::i;:::-;218659:254;;;;;;;217803:1126;218949:15;218945:287;;;218992:224;219038:9;219070:7;219100:6;219129:12;-1:-1:-1;;;218992:23:0;:224::i;:::-;218985:231;;;;218945:287;219252:13;219248:283;;;219293:222;219337:9;219369:7;219399:6;219428:12;-1:-1:-1;;;219293:21:0;:222::i;219248:283::-;217573:1969;;;219561:136;219587:9;219611:7;219633:6;219654:12;219681:5;219561:11;:136::i;:::-;217318:2387;;;;;:::o;38845:348::-;38931:4;38952:11;38948:55;;-1:-1:-1;38987:4:0;38980:11;;38948:55;39019:12;39025:5;39019;:12::i;:::-;39015:171;;;39048:37;;-1:-1:-1;;;;;39048:29:0;;;:37;;;;;39078:6;;39048:37;;;;39078:6;39048:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39048:37:0;39015:171;;;39118:30;-1:-1:-1;;;;;39118:18:0;;39137:2;39141:6;39118:30;:18;:30;:::i;:::-;-1:-1:-1;39170:4:0;39015:171;38845:348;;;;;:::o;41621:166::-;41672:4;-1:-1:-1;;;;;41697:39:0;;;;:81;;-1:-1:-1;;;;;;41740:38:0;;38793:42;41740:38;41697:81;41689:90;;41621:166;;;;:::o;13119:136::-;13177:7;13204:43;13208:1;13211;13204:43;;;;;;;;;;;;;;;;;:3;:43::i;35500:204::-;35627:68;;;-1:-1:-1;;;;;35627:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;35627:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;35601:95:0;;35620:5;;35601:18;:95::i;41795:118::-;41849:4;41878:1;-1:-1:-1;;;;;41873:6:0;:1;-1:-1:-1;;;;;41873:6:0;;:32;;;;41884:8;41890:1;41884:5;:8::i;:::-;:20;;;;;41896:8;41902:1;41896:5;:8::i;69584:117::-;69675:12;69674:19;;;69584:117::o;219713:1027::-;219913:23;;:::i;:::-;:147;;;;;;;;;-1:-1:-1;;;219954:40:0;;-1:-1:-1;219954:40:0;;;;;;219913:147;;-1:-1:-1;;;;;219954:37:0;;;;;:40;;;;;;;;;;;;:37;:40;;;5:2:-1;;;;30:1;27;20:12;5:2;219954:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;219954:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;219954:40:0;-1:-1:-1;;;;;219913:147:0;;;;;220009:40;;;-1:-1:-1;;;220009:40:0;;220047:1;220009:40;;;;;;219954;219913:147;;;;220009:37;;;;;;:40;;;;;;;;;;;:37;:40;;;5:2:-1;;;;30:1;27;20:12;5:2;220009:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;220009:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;220009:40:0;-1:-1:-1;;;;;219913:147:0;;;;;;220148:16;;;220162:1;220148:16;;;220009:40;220148:16;;;;;;-1:-1:-1;;;220073:102:0;;;;;;;;;;;;;;;;;;;;;;219913:147;;-1:-1:-1;220073:39:0;;;;;;220127:6;;220073:102;;;;;;;;220148:16;220073:102;;;;;;220148:16;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;220073:102:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;220073:102:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;220073:102:0;;;;220188:21;220226:12;:19;220212:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;220212:34:0;-1:-1:-1;220188:58:0;-1:-1:-1;220262:6:0;220257:476;220278:1;220274;:5;220257:476;;;220307:21;220318:6;220325:1;220318:9;;;;;;;;;;;-1:-1:-1;;;;;220307:10:0;;;:21;:10;:21;:::i;:::-;220303:70;;;220349:8;;220303:70;220394:6;220389:127;220410:12;:19;220406:1;:23;220389:127;;;220486:1;220490;220486:5;220466:12;220479:1;220466:15;;;;;;;;;;;;;;:26;;220496:4;220465:35;220455:4;220460:1;220455:7;;;;;;;;;;;;;;;;;:45;220431:3;;220389:127;;;;220532:189;220562:6;220569:1;220562:9;;;;;;;;;;;220590:7;220616:43;220653:4;220616:6;220623:1;220616:9;;;;;;;;;;;-1:-1:-1;;;;;220616:28:0;;:43;:28;:43;:::i;:::-;220678:4;220701:5;220532:11;:189::i;:::-;220281:3;;220257:476;;;;219713:1027;;;;;;;:::o;220748:1638::-;220948:23;;:::i;:::-;:147;;;;;;;;;-1:-1:-1;;;220989:40:0;;-1:-1:-1;220989:40:0;;;;;;220948:147;;-1:-1:-1;;;;;220989:37:0;;;;;:40;;;;;;;;;;;;:37;:40;;;5:2:-1;;;;30:1;27;20:12;5:2;220989:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;220989:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;220989:40:0;-1:-1:-1;;;;;220948:147:0;;;;;221044:40;;;-1:-1:-1;;;221044:40:0;;221082:1;221044:40;;;;;;220989;220948:147;;;;221044:37;;;;;;:40;;;;;;;;;;;:37;:40;;;5:2:-1;;;;30:1;27;20:12;5:2;221044:40:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;221044:40:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;221044:40:0;-1:-1:-1;;;;;220948:147:0;;;221185:16;;;221199:1;221185:16;;;221158:24;221185:16;;;;;220948:147;;-1:-1:-1;221185:16:0;;;;;;;105:10:-1;221185:16:0;88:34:-1;136:17;;-1:-1;;221158:43:0;-1:-1:-1;221225:13:0;:6;221236:1;221225:13;:10;:13;:::i;:::-;221212:7;221220:1;221212:10;;;;;;;;;;;;;:26;;;;;221262:22;221273:7;221281:1;221273:10;;;;;;;;;;;;;;221262:6;:10;;:22;;;;:::i;:::-;221249:7;221257:1;221249:10;;;;;;;;;;;;;:35;;;;;221295:21;221333:12;:19;221319:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;221319:34:0;-1:-1:-1;221295:58:0;-1:-1:-1;221369:6:0;221364:593;221385:1;221381;:5;221364:593;;;221414:23;221427:6;221434:1;221427:9;;;;;;;;;;;-1:-1:-1;;;;;221414:12:0;;;:23;:12;:23;:::i;:::-;221410:72;;;221458:8;;221410:72;221503:6;221498:127;221519:12;:19;221515:1;:23;221498:127;;;221595:1;221599;221595:5;221575:12;221588:1;221575:15;;;;;;;;;;;;;;:26;;221605:4;221574:35;221564:4;221569:1;221564:7;;;;;;;;;;;;;;;;;:45;221540:3;;221498:127;;;;221641:158;221671:9;221699:6;221706:1;221699:9;;;;;;;;;;;221727:7;221735:1;221727:10;;;;;;;;;;;;;;221756:4;221779:5;221641:11;:158::i;:::-;221829:43;221866:4;221829:6;221836:1;221829:9;;;;;;:43;221816:7;221824:1;221816:10;;;;;;;;;;;;;:56;;;;;221887:58;221922:9;221934:7;221942:1;221934:10;;;;;;;;;;;;;;221887:6;221894:1;221887:9;;;;;;;;;;;-1:-1:-1;;;;;221887:26:0;;:58;;:26;:58;:::i;:::-;221388:3;;221364:593;;;-1:-1:-1;221969:16:0;222028:17;:6;222035:1;222028:9;;;;;-1:-1:-1;;;;;222028:15:0;;:17::i;:::-;:34;;222061:1;222028:34;;;222048:7;222056:1;222048:10;;;;;;;;;;;;;;222028:34;221989:17;:6;221996:1;221989:9;;:17;:34;;222022:1;221989:34;;;222009:7;222017:1;222009:10;;;;;;;;;;;;;;221989:34;221988:75;221969:94;;222093:9;-1:-1:-1;;;;;222074:38:0;;222119:8;222143:7;222165:1;222074:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;222074:103:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;222074:103:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;222074:103:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;222195:6:0;;-1:-1:-1;222190:189:0;222211:1;222207;:5;222190:189;;;222234:133;222280:10;222309:43;222346:4;222309:6;222316:1;222309:9;;;;;;:43;222234:6;222241:1;222234:9;;;;;;;;;;;-1:-1:-1;;;;;222234:27:0;;:133;;:27;:133;:::i;:::-;-1:-1:-1;222214:3:0;;222190:189;;;;220748:1638;;;;;;;;;:::o;207342:328::-;207527:135;207550:9;207574;207598:6;207619:12;207646:5;207527:8;:135::i;35316:176::-;35425:58;;;-1:-1:-1;;;;;35425:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;35425:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;35399:85:0;;35418:5;;35399:18;:85::i;:::-;35316:176;;;:::o;13592:192::-;13678:7;13714:12;13706:6;;;;13698:29;;;;-1:-1:-1;;;13698: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;13698:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;13750:5:0;;;13592:192::o;37355:1114::-;37959:27;37967:5;-1:-1:-1;;;;;37959:25:0;;:27::i;:::-;37951:71;;;;;-1:-1:-1;;;37951:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;38096:12;38110:23;38145:5;-1:-1:-1;;;;;38137:19:0;38157:4;38137: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;;;38137: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;;38095:67:0;;;;38181:7;38173:52;;;;;-1:-1:-1;;;38173:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38242:17;;:21;38238:224;;38384:10;38373:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;38373:30:0;38365:85;;;;-1:-1:-1;;;38365:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14974:132;15032:7;15059:39;15063:1;15066;15059:39;;;;;;;;;;;;;;;;;:3;:39::i;40277:518::-;40370:12;40376:5;40370;:12::i;:::-;40365:423;;40403:11;40399:101;;40435:24;-1:-1:-1;;;;;40435:17:0;;40453:2;40457:1;40435:24;:17;:24;:::i;:::-;40478:7;;40399:101;40536:34;;;-1:-1:-1;;;40536:34:0;;40560:4;40536:34;;;;-1:-1:-1;;;;;40536:34:0;;;;;;;;;40516:17;;40536:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;40536:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;40536:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;40536:34:0;;-1:-1:-1;40589:18:0;;;40585:192;;;40632:13;;40628:86;;40670:24;-1:-1:-1;;;;;40670:17:0;;40688:2;40692:1;40670:24;:17;:24;:::i;:::-;40732:29;-1:-1:-1;;;;;40732:17:0;;40750:2;40754:6;40732:29;:17;:29;:::i;207678:1928::-;207882:9;-1:-1:-1;;;;;207869:22:0;:9;-1:-1:-1;;;;;207869:22:0;;207865:61;;;207908:7;;207865:61;207988:29;:5;7796:13;207988:29;:11;:29;:::i;:::-;207942:75;;:42;:5;6679:10;207942:42;:11;:42;:::i;:::-;:75;;;207938:1503;;;208034:17;208054:33;208077:9;208054:22;:33::i;:::-;208034:53;-1:-1:-1;;;;;;208106:24:0;;;;208102:533;;208164:9;-1:-1:-1;;;;;208151:31:0;;208183:6;208151:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;208151:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208151:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208209:15:0;;-1:-1:-1;208227:44:0;-1:-1:-1;;;;;208227:29:0;;208265:4;208227:44;:29;:44;:::i;:::-;208209:62;-1:-1:-1;;;;;;208294:18:0;;70357:42;208294:18;208290:89;;;70357:42;-1:-1:-1;;;;;208337:13:0;;208351:7;208337:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;208337:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208337:22:0;;;;208290:89;208397:222;-1:-1:-1;;;;;208429:18:0;;70357:42;208429:18;208428:47;;208465:10;208428:47;;;70089:42;208428:47;208498:9;208530:7;208560:12;208595:5;208397:8;:222::i;:::-;208102:533;;208664:33;208687:9;208664:22;:33::i;:::-;208651:46;-1:-1:-1;;;;;;208716:24:0;;;;208712:718;;208761:224;208795:9;-1:-1:-1;;;;;208828:18:0;;70357:42;208828:18;208827:47;;208864:10;208827:47;;;70089:42;208827:47;208897:6;208926:12;208961:5;208761:11;:224::i;:::-;209006:24;209033:83;209110:4;-1:-1:-1;;;;;209035:18:0;;70357:42;209035:18;209034:47;;209071:10;209034:47;;;70089:42;209034:47;-1:-1:-1;;;;;209033:68:0;;:83;:68;:83;:::i;:::-;209006:110;;209135:103;209258:65;-1:-1:-1;;;;;209258:27:0;;209294:9;209306:16;209258:65;:27;:65;:::i;:::-;209355:9;-1:-1:-1;;;;;209342:29:0;;209372:16;209342:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;209342:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;209342:47:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;209408:7:0;;-1:-1:-1;;;209408:7:0;208712:718;207938:1503;;209460:138;209486:9;209510;209534:6;209555:12;209582:5;209460:11;:138::i;32345:619::-;32405:4;32873:20;;32716:66;32913:23;;;;;;:42;;-1:-1:-1;32940:15:0;;;32913:42;32905:51;32345:619;-1:-1:-1;;;;32345:619:0:o;15636:345::-;15722:7;15824:12;15817:5;15809:28;;;;-1:-1:-1;;;15809:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;15809:28:0;;15848:9;15864:1;15860;:5;;;;;;;15636:345;-1:-1:-1;;;;;15636:345:0:o;35712:621::-;36082:10;;;36081:62;;-1:-1:-1;36098:39:0;;;-1:-1:-1;;;36098:39:0;;36122:4;36098:39;;;;-1:-1:-1;;;;;36098:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;36098:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;36098:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;36098:39:0;:44;36081:62;36073:152;;;;-1:-1:-1;;;36073:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;36262:62;;;-1:-1:-1;;;;;36262:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;36262:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;36236:89:0;;36255:5;;36236:18;:89::i;203293:455::-;203465:128;;;-1:-1:-1;;;;;203465:128:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;203465:128:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;203416:188:0;;;;203361:6;;;;203395:17;;203241:42;;203465:128;;203416:188;;;;25:18:-1;203416: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;;;203416: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;;203380:224:0;;;;203622:7;203621:8;:28;;;-1:-1:-1;203633:11:0;;:16;203621:28;203617:78;;;-1:-1:-1;;203666:17:0;;;;;;203617:78;203725:4;203714:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;203714:26:0;;203293:455;-1:-1:-1;;;;203293:455:0:o;193993:329::-;194178:136;194202:9;194226;194250:6;194271:12;194298:5;194330:1972;194535:9;-1:-1:-1;;;;;194522:22:0;:9;-1:-1:-1;;;;;194522:22:0;;194518:61;;;194561:7;;194518:61;194641:30;:5;5708:7;194641:30;:11;:30;:::i;:::-;194595:76;;:42;:5;6679:10;194595:42;:11;:42;:::i;:::-;:76;;;194591:1546;;;-1:-1:-1;;;;;194692:17:0;;70357:42;194692:17;194688:334;;;194744:29;;;-1:-1:-1;;;194744:29:0;;194767:4;194744:29;;;;;;70357:42;;194730:13;;70357:42;;194744:14;;:29;;;;;;;;;;;;;;70357:42;194744:29;;;5:2:-1;;;;30:1;27;20:12;5:2;194744:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;194744:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194744:29:0;194730:44;;;-1:-1:-1;;;;;;194730:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;194730:44:0;;;;;;;-1:-1:-1;194730:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;194730:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;194730:44:0;;;;194793:188;70089:42;194861:9;194893:6;194922:12;194957:5;194793:11;:188::i;:::-;195000:7;;194688:334;-1:-1:-1;;;;;195042:29:0;;70270:42;195042:29;195038:370;;;195118:41;;;-1:-1:-1;;;195118:41:0;;195153:4;195118:41;;;;;;70270:42;;195092:25;;70270:42;;195118:26;;:41;;;;;;;;;;;;;;70270:42;195118:41;;;5:2:-1;;;;30:1;27;20:12;195038:370:0;-1:-1:-1;;;;;195428:17:0;;70357:42;195428:17;195424:331;;;195466:186;195498:9;70089:42;195564:6;195593:12;195628:5;195466:9;:186::i;:::-;70357:42;-1:-1:-1;;;;;195671:12:0;;195690:21;195671:43;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;195671:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;195424:331:0;-1:-1:-1;;;;;195775:29:0;;70270:42;195775:29;195771:355;;;195825:186;195857:9;70089:42;195923:6;195952:12;195987:5;195825:9;:186::i;:::-;70270:42;-1:-1:-1;;;;;196030:24:0;;196061:21;196030:55;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;195771:355:0;196156:138;196182:9;196206;196230:6;196251:12;196278:5;185283:329;185468:136;185492:9;185516;185540:6;185561:12;185588:5;185620:1426;185861:30;:5;6177:8;185861:30;:11;:30;:::i;:::-;185860:31;185814:42;:5;6679:10;185814:42;:11;:42;:::i;:::-;185813:43;:78;185809:1148;;;185908:22;;:::i;:::-;185933:13;:11;:13::i;:::-;185908:38;-1:-1:-1;185968:6:0;185963:401;185984:13;185980:1;:17;185963:401;;;186047:6;186054:1;186047:9;;;;;;;;;;;-1:-1:-1;;;;;186027:30:0;:9;-1:-1:-1;;;;;186027:30:0;;186023:326;;;186082:17;186102:6;186109:1;186102:9;;;;;;;;;;;-1:-1:-1;;;;;186102:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186102:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186102:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186102:17:0;;-1:-1:-1;186142:14:0;186159:6;186166:1;186159:9;;;;;;;;;;;-1:-1:-1;;;;;186159:25:0;;186185:6;186193:4;186213:1;186199:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186199:16:0;;186159: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;186159:57:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186159:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186159:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186159:57:0;;-1:-1:-1;186239:61:0;186249:10;186261:9;186159:57;186280:12;186294:5;186239:9;:61::i;:::-;186323:7;;;;;;186023:326;185999:3;;185963:401;;;-1:-1:-1;186385:6:0;186380:566;186401:13;186397:1;:17;186380:566;;;186464:6;186471:1;186464:9;;;;;;;;;;;-1:-1:-1;;;;;186444:30:0;:9;-1:-1:-1;;;;;186444:30:0;;186440:491;;;186499:17;186519:6;186526:1;186519:9;;;;;;;;;;;-1:-1:-1;;;;;186519:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186519:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186519:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186519:17:0;;-1:-1:-1;186559:63:0;186571:9;186519:17;186594:6;186602:12;186616:5;186559:11;:63::i;:::-;186675:35;;;-1:-1:-1;;;186675:35:0;;186704:4;186675:35;;;;;;186647:25;;-1:-1:-1;;;;;186675:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;186675:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186675:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186675:35:0;;-1:-1:-1;186733:66:0;186769:6;186776:1;186769:9;;;;;;;;;;;-1:-1:-1;;;;;186733:27:0;;;186781:17;186733:66;:27;:66;:::i;:::-;186822:6;186829:1;186822:9;;;;;;;;;;;-1:-1:-1;;;;;186822:23:0;;186846:17;186879:1;186865:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186865:16:0;;186822: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;186822:60:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186822:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186822:60:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186905:7:0;;-1:-1:-1;;;;;186905:7:0;186440:491;186416:3;;186380:566;;;;185809:1148;;186976:62;186988:9;186999;187010:6;187018:12;187032:5;186976:11;:62::i;181426:716::-;181471:15;;:::i;:::-;-1:-1:-1;181566:568:0;;;;;;;;181613:42;181566:568;;181677:42;181566:568;;;;181741:42;181566:568;;;;;;;181805:42;181566:568;;;;181869:42;181566:568;;;;181933:42;181566:568;;;;182016:42;181566:568;;;;182080:42;181566:568;;;;181426:716;:::o;178966:330::-;179151:137;179176:9;179200;179224:6;179245:12;179272:5;179304:1465;179510:9;-1:-1:-1;;;;;179497:22:0;:9;-1:-1:-1;;;;;179497:22:0;;179493:61;;;179536:7;;179493:61;179616:31;:5;5080;179616:31;:11;:31;:::i;:::-;179570:77;;:42;:5;6679:10;179570:42;:11;:42;:::i;:::-;:77;;;179566:1114;;;179664:25;;:::i;:::-;179692:10;:8;:10::i;:::-;179664:38;-1:-1:-1;179724:6:0;179719:387;179740:14;179736:1;:18;179719:387;;;179804:7;179812:1;179804:10;;;;;;;;;;;-1:-1:-1;;;;;179784:31:0;:9;-1:-1:-1;;;;;179784:31:0;;179780:311;;;179840:17;179860:7;179868:1;179860:10;;;;;;;;;;;-1:-1:-1;;;;;179860:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;179860:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179860:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179860:18:0;;-1:-1:-1;179901:7:0;179909:1;179901:10;;;;;;;;;;;-1:-1:-1;;;;;179901:19:0;;179921:6;179901:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;179901:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179901:27:0;;;;179951:91;179962:10;179974:9;179985:10;-1:-1:-1;;;;;179985:20:0;;180014:4;179985:35;;;;;;;;;;;;;-1:-1:-1;;;;;179985:35:0;-1:-1:-1;;;;;179985:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;179985:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179985:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;179985:35:0;180022:12;180036:5;179951:10;:91::i;:::-;180065:7;;;;;179780:311;179756:3;;179719:387;;;-1:-1:-1;180127:6:0;180122:547;180143:14;180139:1;:18;180122:547;;;180207:7;180215:1;180207:10;;;;;;;;;;;-1:-1:-1;;;;;180187:31:0;:9;-1:-1:-1;;;;;180187:31:0;;180183:471;;;180243:17;180263:7;180271:1;180263:10;;;;;;;;;;;-1:-1:-1;;;;;180263:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;180263:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;180263:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180263:18:0;;-1:-1:-1;180304:63:0;180316:9;180263:18;180339:6;180347:12;180361:5;180304:11;:63::i;:::-;180420:35;;;-1:-1:-1;;;180420:35:0;;180449:4;180420:35;;;;;;180392:25;;-1:-1:-1;;;;;180420:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;180420:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;180420:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180420:35:0;;-1:-1:-1;180478:67:0;180514:7;180522:1;180514:10;;;;;;180478:67;180568:7;180576:1;180568:10;;;;;;;;;;;-1:-1:-1;;;;;180568:18:0;;180587:17;180568:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;180568:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;180568:37:0;;;;180628:7;;;;;;180183:471;180159:3;;180122:547;;;;179566:1114;;180699:62;180711:9;180722;180733:6;180741:12;180755:5;180699:11;:62::i;174531:943::-;174573:17;;:::i;:::-;-1:-1:-1;174603:863:0;;;;;;;;174632:42;174603:863;;174697:42;174603:863;;;;174762:42;174603:863;;;;;;;174827:42;174603:863;;;;174892:42;174603:863;;;;174957:42;174603:863;;;;175022:42;174603:863;;;;175087:42;174603:863;;;;175152:42;174603:863;;;;175217:42;174603:863;;;;175282:42;174603:863;;;;175347:42;174603:863;;;;175412:42;174603:863;;;;174531:943;:::o;156974:333::-;157159:140;157187:9;157211;157235:6;157256:12;157283:5;157315:1867;157524:9;-1:-1:-1;;;;;157511:22:0;:9;-1:-1:-1;;;;;157511:22:0;;157507:61;;;157550:7;;157507:61;157630:34;:5;4610:4;157630:34;:11;:34;:::i;:::-;157584:80;;:42;:5;6679:10;157584:42;:11;:42;:::i;:::-;:80;;;157580:1437;;;157701:66;;;-1:-1:-1;;;157701:66:0;;-1:-1:-1;;;;;157701:66:0;;;;;;;;157681:17;;74956:42;;157701:30;;:66;;;;;;;;;;;;;;;74956:42;157701:66;;;5:2:-1;;;;30:1;27;20:12;5:2;157701:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157701:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157701:66:0;;-1:-1:-1;;;;;;157786:23:0;;;157782:430;;157853:9;-1:-1:-1;;;;;157830:41:0;;157872:6;157830:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;157830:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157830:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157898:24:0;;-1:-1:-1;157925:44:0;-1:-1:-1;;;;;157925:29:0;;157963:4;157925:44;:29;:44;:::i;:::-;157898:71;;157997:199;158033:10;158066:9;158098:16;158137:12;158172:5;157997:13;:199::i;157782:430::-;158241:66;;;-1:-1:-1;;;158241:66:0;;-1:-1:-1;;;;;158241:66:0;;;;;;;;74956:42;;158241:30;;:66;;;;;;;;;;;;;;74956:42;158241:66;;;5:2:-1;;;;30:1;27;20:12;5:2;158241:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;158241:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;158241:66:0;;-1:-1:-1;;;;;;158326:23:0;;;158322:684;;158370:187;158404:9;158436:10;158469:6;158498:12;158533:5;158370:11;:187::i;:::-;158578:24;158605:44;-1:-1:-1;;;;;158605:29:0;;158643:4;158605:44;:29;:44;:::i;:::-;158578:71;;158674:18;:10;-1:-1:-1;;;;;158674:16:0;;:18::i;:::-;158670:296;;;73906:42;-1:-1:-1;;;;;158717:9:0;;158733:16;158717:35;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;158717:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;158717:35:0;;;;;158670:296;;158322:684;157580:1437;;159036:138;159062:9;159086;159110:6;159131:12;159158:5;164209:332;164394:139;164421:9;164445;164469:6;164490:12;164517:5;164757:9;-1:-1:-1;;;;;164744:22:0;:9;-1:-1:-1;;;;;164744:22:0;;164740:61;;;164783:7;;164740:61;164863:33;:5;4670:4;164863:33;:11;:33;:::i;:::-;164817:79;;:42;:5;6679:10;164817:42;:11;:42;:::i;:::-;:79;;;164813:1618;;;164913:17;164933:26;164949:9;164933:15;:26::i;:::-;164913:46;-1:-1:-1;;;;;;164978:24:0;;;;164974:626;;165027:18;:10;-1:-1:-1;;;;;165027:16:0;;:18::i;:::-;165023:245;;;165070:68;;;-1:-1:-1;;;165070:68:0;;165124:4;165070:68;;;;;;;;;;;;-1:-1:-1;;;;;165070:45:0;;;;;:68;;;;;;;;;;;;;;-1:-1:-1;165070:45:0;:68;;;5:2:-1;;;;30:1;27;20:12;5:2;165070:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165070:68:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165023:245:0;;-1:-1:-1;165023:245:0;;165187:61;;;-1:-1:-1;;;165187:61:0;;165234:4;165187:61;;;;;;;;;;;;-1:-1:-1;;;;;165187:38:0;;;;;:61;;;;;;;;;;;;;;-1:-1:-1;165187:38:0;:61;;;5:2:-1;;;;30:1;27;20:12;5:2;165187:61:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165187:61:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;165023:245:0;165288:24;165315:44;-1:-1:-1;;;;;165315:29:0;;165353:4;165315:44;:29;:44;:::i;:::-;165288:71;;165387:197;165421:10;165454:9;165486:16;165525:12;165560:5;165387:11;:197::i;164974:626::-;165629:26;165645:9;165629:15;:26::i;:::-;165616:39;-1:-1:-1;;;;;;165674:24:0;;;;165670:750;;165719:187;165753:9;165785:10;165818:6;165847:12;165882:5;165719:11;:187::i;:::-;165927:24;165954:44;-1:-1:-1;;;;;165954:29:0;;165992:4;165954:44;:29;:44;:::i;:::-;165927:71;;166023:18;:10;-1:-1:-1;;;;;166023:16:0;;:18::i;:::-;166019:361;;;166066:86;;;-1:-1:-1;;;166066:86:0;;166146:4;166066:86;;;;;;-1:-1:-1;;;;;166066:47:0;;;;;166120:16;;166066:86;;;;;;;;;;;;;;;166120:16;166066:47;:86;;;5:2:-1;;;;30:1;27;20:12;5:2;166066:86:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;166066:86:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;166019:361:0;;-1:-1:-1;166019:361:0;;166201:65;-1:-1:-1;;;;;166201:27:0;;166237:9;166249:16;166201:65;:27;:65;:::i;:::-;166289:71;;;-1:-1:-1;;;166289:71:0;;166336:4;166289:71;;;;;;;;;;;;-1:-1:-1;;;;;166289:38:0;;;;;:71;;;;;;;;;;;;;;-1:-1:-1;166289:38:0;:71;;;5:2:-1;;;;30:1;27;20:12;165670:750:0;164813:1618;;166450:138;166476:9;166500;166524:6;166545:12;166572:5;166450:11;:138::i;160010:1173::-;160071:6;160094:13;:5;-1:-1:-1;;;;;160094:11:0;;:13::i;:::-;160090:63;;;-1:-1:-1;;;160124:17:0;;160090:63;160237:57;;;22:32:-1;6:49;;160237:57:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;160201:94:0;;;;160166:12;;160180:17;;-1:-1:-1;;;;;160201:25:0;;;160231:4;;160237:57;;160201:94;;;;25:18:-1;160201: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;;;160201: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;;160165:130:0;;;;160311:7;160306:58;;-1:-1:-1;;160335:17:0;;;;;;160306:58;160376:13;;160408:414;160433:4;:11;160425:1;160429;160425:5;:19;160408:414;;;160470:4;160475:1;160479;160475:5;160470:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160470:11:0;-1:-1:-1;;;160470:18:0;:57;;;;;160509:4;160514:1;160518;160514:5;160509:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160509:11:0;-1:-1:-1;;;160509:18:0;160470:57;:96;;;;;160548:4;160553:1;160557;160553:5;160548:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160548:11:0;-1:-1:-1;;;160548:18:0;160470:96;:135;;;;;160587:4;160592:1;160596;160592:5;160587:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160587:11:0;-1:-1:-1;;;160587:18:0;160470:135;:174;;;;;160626:4;160631:1;160635;160631:5;160626:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160626:11:0;-1:-1:-1;;;160626:18:0;160470:174;:213;;;;;160665:4;160670:1;160674;160670:5;160665:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160665:11:0;-1:-1:-1;;;160665:18:0;160470:213;:252;;;;;160704:4;160709:1;160713;160709:5;160704:11;;;;;;;;;;;;;-1:-1:-1;;;;;;160704:11:0;-1:-1:-1;;;160704:18:0;160470:252;160466:345;;;160767:4;160756:15;;160790:5;;160466:345;160446:3;;160408:414;;;;160837:8;160832:59;;-1:-1:-1;;160862:17:0;;;;;;;160832:59;160957:103;;;22:32:-1;6:49;;160957:103:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;160921:140:0;;;;-1:-1:-1;;;;;160921:25:0;;;160951:4;;160957:103;160921:140;;;25:18:-1;160921: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;;;160921: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;160903:158:0;;-1:-1:-1;160903:158:0;-1:-1:-1;160903:158:0;161072:58;;-1:-1:-1;;161101:17:0;;;;;;;161072:58;161160:4;161149:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;161149:26:0;;160010:1173;-1:-1:-1;;;;;160010:1173:0:o;189831:329::-;190016:136;190040:9;190064;190088:6;190109:12;190136:5;190168:1731;190373:9;-1:-1:-1;;;;;190360:22:0;:9;-1:-1:-1;;;;;190360:22:0;;190356:61;;;190399:7;;190356:61;190479:30;:5;4784:4;190479:30;:11;:30;:::i;:::-;190433:76;;:42;:5;6679:10;190433:42;:11;:42;:::i;:::-;:76;;;190429:1305;;;190546:58;;;-1:-1:-1;;;190546:58:0;;-1:-1:-1;;;;;190546:58:0;;;;;;;;190526:17;;75067:42;;190546:26;;:58;;;;;;;;;;;;;;;75067:42;190546:58;;;5:2:-1;;;;30:1;27;20:12;5:2;190546:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;190546:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;190546:58:0;;-1:-1:-1;;;;;;190623:23:0;;;190619:322;;190686:9;-1:-1:-1;;;;;190667:37:0;;190705:6;190667:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190667:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;190667:45:0;;;;190740:185;190772:10;190805:9;190837:6;190866:12;190901:5;190740:9;:185::i;:::-;190733:192;;;190619:322;190970:58;;;-1:-1:-1;;;190970:58:0;;-1:-1:-1;;;;;190970:58:0;;;;;;;;75067:42;;190970:26;;:58;;;;;;;;;;;;;;75067:42;190970:58;;;5:2:-1;;;;30:1;27;20:12;5:2;190970:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;190970:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;190970:58:0;;-1:-1:-1;;;;;;191047:23:0;;;191043:680;;191091:187;191125:9;191157:10;191190:6;191219:12;191254:5;191091:11;:187::i;:::-;191299:24;191326:44;-1:-1:-1;;;;;191326:29:0;;191364:4;191326:44;:29;:44;:::i;:::-;191299:71;;191391:58;73702:42;-1:-1:-1;;;;;191419:9:0;;:11;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;191419:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;191419:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;191419:11:0;-1:-1:-1;;;;;191391:27:0;;;191432:16;191391:58;:27;:58;:::i;:::-;73702:42;191468:12;191487:18;-1:-1:-1;;;;;191487:16:0;;;:18::i;:::-;:41;;191527:1;191487:41;;;191508:16;191487:41;191552:18;:10;-1:-1:-1;;;;;191552:16:0;;:18::i;:::-;:45;;191587:10;191552:45;;;70089:42;191552:45;191468:214;;;-1:-1:-1;;;;;;191468:214:0;;;;;;;-1:-1:-1;;;;;191468:214:0;;;;;;;;;;;;;191659:4;191468:214;;;;;;;;;;-1:-1:-1;;191468:214:0;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;191468:214:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;191468:214:0;;;;;191701:7;;;;191043:680;190429:1305;;191753:138;191779:9;191803;191827:6;191848:12;191875:5;172375:1707;172577:9;-1:-1:-1;;;;;172564:22:0;:9;-1:-1:-1;;;;;172564:22:0;;172560:61;;;172603:7;;172560:61;172683:30;:5;5021;172683:30;:11;:30;:::i;:::-;172637:76;;:42;:5;6679:10;172637:42;:11;:42;:::i;:::-;:76;;;172633:1360;;;-1:-1:-1;;;;;172734:25:0;;170326:42;172734:25;172730:913;;;170326:42;-1:-1:-1;;;;;172780:9:0;;172790:6;172780:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;172780:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;172839:28:0;;;-1:-1:-1;;;172839:28:0;;172861:4;172839:28;;;;;;172818:18;;-1:-1:-1;170414:42:0;;-1:-1:-1;172839:13:0;;:28;;;;;;;;;;;;;;;170414:42;172839:28;;;5:2:-1;;;;30:1;27;20:12;5:2;172839:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;172839:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;172839:28:0;;-1:-1:-1;172890:14:0;;172886:534;;172931:32;172967:203;170414:42;173041:9;173077:10;173114:1;173142:5;172967:17;:203::i;:::-;172929:241;;;173195:205;170414:42;173257:9;173293:10;173330:15;173372:5;173195;:205::i;:::-;172886:534;;173447:180;-1:-1:-1;;;;;;;;;;;173507:9:0;173539:6;173568:12;173603:5;173447:11;:180::i;172730:913::-;-1:-1:-1;;;;;173663:25:0;;170326:42;173663:25;173659:323;;;173709:56;173721:9;-1:-1:-1;;;;;;;;;;;173737:6:0;173745:12;173759:5;173709:11;:56::i;:::-;173807:28;;;-1:-1:-1;;;173807:28:0;;173829:4;173807:28;;;;;;173786:18;;-1:-1:-1;;;;;;;;;;;70532:42:0;173807:13;;:28;;;;;;;;;;;;;;;70532:42;173807:28;;;5:2:-1;;;;30:1;27;20:12;5:2;173807:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;173807:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;173807:28:0;;-1:-1:-1;173854:47:0;-1:-1:-1;;;;;;;;;;;170326:42:0;173807:28;173854:47;:20;:47;:::i;:::-;170326:42;-1:-1:-1;;;;;173920:9:0;;173930:10;173920:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;173659:323:0;174012:62;174024:9;174035;174046:6;174054:12;174068:5;168656:1337;168858:9;-1:-1:-1;;;;;168845:22:0;:9;-1:-1:-1;;;;;168845:22:0;;168841:61;;;168884:7;;168841:61;168964:30;:5;4727:4;168964:30;:11;:30;:::i;:::-;168918:76;;:42;:5;6679:10;168918:42;:11;:42;:::i;:::-;:76;;;168914:914;;;-1:-1:-1;;;;;169015:25:0;;70444:42;169015:25;169011:328;;;169061:32;;;-1:-1:-1;;;169061:32:0;;169079:4;169061:32;;;;;;;;;;;;70444:42;;169061:9;;:32;;;;;-1:-1:-1;;169061:32:0;;;;;;;-1:-1:-1;70444:42:0;169061:32;;;5:2:-1;;;;30:1;27;20:12;5:2;169061:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;169213:28:0;;;-1:-1:-1;;;169213:28:0;;169235:4;169213:28;;;;;;169121:202;;-1:-1:-1;;;;;;;;;;;;70532:42:0;-1:-1:-1;169181:9:0;;70532:42;;169213:13;;:28;;;;;;;;;;;;;;;70532:42;169213:28;;;5:2:-1;;;;30:1;27;20:12;5:2;169213:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169213:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169213:28:0;169264:12;169299:5;169121:11;:202::i;169011:328::-;-1:-1:-1;;;;;169359:25:0;;70444:42;169359:25;169355:462;;;169405:180;169439:9;-1:-1:-1;;;;;;;;;;;169497:6:0;169526:12;169561:5;169405:11;:180::i;:::-;169627:28;;;-1:-1:-1;;;169627:28:0;;169649:4;169627:28;;;;;;169606:18;;-1:-1:-1;;;;;;;;;;;70532:42:0;169627:13;;:28;;;;;;;;;;;;;;;70532:42;169627:28;;;5:2:-1;;;;30:1;27;20:12;5:2;169627:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169627:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169627:28:0;;-1:-1:-1;169674:47:0;-1:-1:-1;;;;;;;;;;;70444:42:0;169627:28;169674:47;:20;:47;:::i;:::-;169740:36;;;-1:-1:-1;;;169740:36:0;;169758:4;169740:36;;;;;;;;;;;;70444:42;;169740:9;;:36;;;;;-1:-1:-1;;169740:36:0;;;;;;;-1:-1:-1;70444:42:0;169740:36;;;5:2:-1;;;;30:1;27;20:12;169355:462:0;169847:138;169873:9;169897;169921:6;169942:12;169969:5;200197:2445;200399:9;-1:-1:-1;;;;;200386:22:0;:9;-1:-1:-1;;;;;200386:22:0;;200382:61;;;200425:7;;200382:61;200505:38;:5;7659:13;200505:38;:11;:38;:::i;:::-;200459:84;;:42;:5;6679:10;200459:42;:11;:42;:::i;:::-;:84;;;200455:2022;;;-1:-1:-1;;;;;200564:25:0;;74346:42;200564:25;200560:937;;;-1:-1:-1;;;;;200614:17:0;;70621:42;200614:17;;:37;;-1:-1:-1;;;;;;200635:16:0;;-1:-1:-1;;;;;;;;;;;200635:16:0;200614:37;:58;;;-1:-1:-1;;;;;;200655:17:0;;70710:42;200655:17;200614:58;:79;;;-1:-1:-1;;;;;;200676:17:0;;70799:42;200676:17;200614:79;200610:847;;;200741:59;;;-1:-1:-1;;;200741:59:0;;-1:-1:-1;;;;;200741:59:0;;;;;;;;;;;;;;;;;;;;;200723:14;;74476:42;;200741:29;;:59;;;;;200723:14;;200741:59;;;;;;;;74476:42;200741:59;;;5:2:-1;;;;30:1;27;20:12;5:2;200741:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;200741:59:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;200741:59:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:3;5:12;;2:2;;;30:1;27;20:12;2:2;200741: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;200741:59:0;;420:4:-1;411:14;;;;200741:59:0;;;;;411:14:-1;200741: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;200741:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;200741:59:0;;;;;;;;-1:-1:-1;;;200823:103:0;;-1:-1:-1;;;;;200823:103:0;;;;;;;;;;;;;;200741:59;;-1:-1:-1;74346:42:0;;-1:-1:-1;200823:11:0;;-1:-1:-1;200823:103:0;;;;;-1:-1:-1;200741:59:0;;-1:-1:-1;200823:103:0;;;;;;-1:-1:-1;74346:42:0;200823:103;;;5:2:-1;;;;30:1;27;20:12;5:2;200823:103:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;200823:103:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;200610:847:0;;-1:-1:-1;;200610:847:0;;201015:53;;;-1:-1:-1;;;201015:53:0;;-1:-1:-1;;;;;201015:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;201015:53:0;;;;;;200997:14;;74476:42;;201015:29;;:53;;;;;200997:14;;201015:53;;;;;;;;74476:42;201015:53;;;5:2:-1;;;;30:1;27;20:12;5:2;201015:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;201015:53:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;201015:53:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:3;5:12;;2:2;;;30:1;27;20:12;2:2;201015: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;201015:53:0;;420:4:-1;411:14;;;;201015:53:0;;;;;411:14:-1;201015: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;201015:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;201015:53:0;;;;;;;;-1:-1:-1;;;201091:97:0;;-1:-1:-1;;;;;;;;;;;201091:97:0;;;;;;;;;;;;201015:53;;-1:-1:-1;74346:42:0;;-1:-1:-1;201091:11:0;;-1:-1:-1;201091:97:0;;;;;-1:-1:-1;201015:53:0;;-1:-1:-1;201091:97:0;;;;;;-1:-1:-1;74346:42:0;201091:97;;;5:2:-1;;;;30:1;27;20:12;5:2;201091:97:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;201091:97:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;201315:28:0;;;-1:-1:-1;;;201315:28:0;;201337:4;201315:28;;;;;;201211:226;;-1:-1:-1;;;;;;;;;;;70532:42:0;201279:9;;70532:42;;201315:13;;:28;;;;;201091:97;;201315:28;;;;;;;;70532:42;201315:28;;;5:2:-1;;;;30:1;27;20:12;5:2;201315:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;201315:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;201315:28:0;201370:12;201409:5;201211:11;:226::i;200560:937::-;-1:-1:-1;;;;;201517:25:0;;74346:42;201517:25;201513:953;;;-1:-1:-1;;;;;201567:17:0;;70621:42;201567:17;;:37;;-1:-1:-1;;;;;;201588:16:0;;-1:-1:-1;;;;;;;;;;;201588:16:0;201567:37;:58;;;-1:-1:-1;;;;;;201608:17:0;;70710:42;201608:17;201567:58;:79;;;-1:-1:-1;;;;;;201629:17:0;;70799:42;201629:17;201567:79;201563:863;;;201671:49;-1:-1:-1;;;;;201671:26:0;;74346:42;201713:6;201671:49;:26;:49;:::i;:::-;201743:177;;;-1:-1:-1;;;201743:177:0;;-1:-1:-1;;;;;201743:177:0;;;;;;;;;;;;;;;;;;;201892:4;201743:177;;;;;;74346:42;;201743:9;;:177;;;;;;;;;;;;;;-1:-1:-1;74346:42:0;201743:177;;;5:2:-1;;;;30:1;27;20:12;5:2;201743:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;201743:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;201563:863:0;;-1:-1:-1;201563:863:0;;201986:204;202024:9;-1:-1:-1;;;;;;;;;;;202090:6:0;202123:12;202162:5;201986:11;:204::i;:::-;202315:28;;;-1:-1:-1;;;202315:28:0;;202337:4;202315:28;;;;;;74346:42;;202213:9;;-1:-1:-1;;;;;;;;;;;70532:42:0;202279:9;;70532:42;;202315:13;;:28;;;;;;;;;;;;;;70532:42;202315:28;;;5:2:-1;;;;30:1;27;20:12;5:2;202315:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;202315:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;202315:28:0;202213:193;;;-1:-1:-1;;;;;;202213:193:0;;;;;;;-1:-1:-1;;;;;202213:193:0;;;;;;;;;;;;;;;;;;;202378:4;202213:193;;;;;;;;;;;202315:28;;202213:193;;;;;;;-1:-1:-1;202213:193:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;202213:193:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;202213:193:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;201513:953:0;202496:138;202522:9;202546;202570:6;202591:12;202618:5;127771:437;128007:9;-1:-1:-1;;;;;127994:22:0;:9;-1:-1:-1;;;;;127994:22:0;;127990:61;;;128033:7;;127990:61;128063:137;128088:9;128112;128136:6;128157:12;128184:5;230625:8;;230590:53;;-1:-1:-1;;;;;230590:26:0;;;;230625:8;230636:6;230590:53;:26;:53;:::i;:::-;230654:8;;-1:-1:-1;;;;;230654:8:0;;;;:13;;230674:17;;:15;;;:17::i;:::-;:30;;230703:1;230674:30;;;230694:6;230674:30;230720:9;230744;230768:6;230789:1;230805:12;230832:5;230654:194;;;;;;;;;;;;;-1:-1:-1;;;;;230654:194:0;-1:-1:-1;;;;;230654:194:0;;;;;;-1:-1:-1;;;;;230654:194:0;-1:-1:-1;;;;;230654: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;230654:194:0;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;230654:194:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;230654:194:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;230400:456:0:o;224904:5955::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;224904:5955:0;;;-1:-1:-1;;224904:5955:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;224904:5955:0;;;-1:-1:-1;;224904:5955:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;224904:5955:0;;;-1:-1:-1;;224904:5955:0:o
Swarm Source
bzzr://6f45d82ac1efe97752bbcf64663dc8e548b807529aa81fbe1cb021ecb5106b54
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 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.