Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 10414695 | 1466 days ago | IN | Create: OneSplit | 0 ETH | 0.11000417 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
11153850 | 1352 days ago | 1.5 ETH | ||||
11153850 | 1352 days ago | 1.5 ETH | ||||
11134653 | 1355 days ago | 3.85 ETH | ||||
11134653 | 1355 days ago | 3.85 ETH | ||||
10953725 | 1383 days ago | 3.90809233 ETH | ||||
10953725 | 1383 days ago | 3.90809233 ETH | ||||
10951240 | 1383 days ago | 1.595 ETH | ||||
10951240 | 1383 days ago | 1.595 ETH | ||||
10880786 | 1394 days ago | 9 wei | ||||
10880786 | 1394 days ago | 9 wei | ||||
10880608 | 1394 days ago | 9 wei | ||||
10880608 | 1394 days ago | 9 wei | ||||
10878829 | 1395 days ago | 1 wei | ||||
10878829 | 1395 days ago | 1 wei | ||||
10834163 | 1401 days ago | 5 ETH | ||||
10834163 | 1401 days ago | 5 ETH | ||||
10786635 | 1409 days ago | 1,145 ETH | ||||
10786635 | 1409 days ago | 1,145 ETH | ||||
10747567 | 1415 days ago | 50 ETH | ||||
10747567 | 1415 days ago | 50 ETH | ||||
10747562 | 1415 days ago | 101 ETH | ||||
10747562 | 1415 days ago | 101 ETH | ||||
10747559 | 1415 days ago | 10.1 ETH | ||||
10747559 | 1415 days ago | 10.1 ETH | ||||
10747559 | 1415 days ago | 76.76 ETH |
Loading...
Loading
Contract Name:
OneSplit
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-07-07 */ // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: contracts/IOneSplit.sol pragma solidity ^0.5.0; // // [ msg.sender ] // | | // | | // \_/ // +---------------+ ________________________________ // | OneSplitAudit | _______________________________ \ // +---------------+ \ \ // | | ______________ | | (staticcall) // | | / ____________ \ | | // | | (call) / / \ \ | | // | | / / | | | | // \_/ | | \_/ \_/ // +--------------+ | | +----------------------+ // | OneSplitWrap | | | | OneSplitViewWrap | // +--------------+ | | +----------------------+ // | | | | | | // | | (delegatecall) | | (staticcall) | | (staticcall) // \_/ | | \_/ // +--------------+ | | +------------------+ // | OneSplit | | | | OneSplitView | // +--------------+ | | +------------------+ // | | / / // \ \________________/ / // \__________________/ // contract IOneSplitConsts { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01; uint256 internal constant DEPRECATED_FLAG_DISABLE_KYBER = 0x02; // Deprecated uint256 internal constant FLAG_DISABLE_BANCOR = 0x04; uint256 internal constant FLAG_DISABLE_OASIS = 0x08; uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10; uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20; uint256 internal constant FLAG_DISABLE_CHAI = 0x40; uint256 internal constant FLAG_DISABLE_AAVE = 0x80; uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_BDAI = 0x400; uint256 internal constant FLAG_DISABLE_IEARN = 0x800; uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000; uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000; uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000; uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000; uint256 internal constant FLAG_DISABLE_WETH = 0x80000; uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH uint256 internal constant FLAG_DISABLE_IDLE = 0x800000; uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000; uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000; uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000; uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000; uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000; uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000; uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000; uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000; uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000; uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000; uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Deprecated, Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Deprecated, Turned off by default uint256 internal constant FLAG_DISABLE_KYBER_ALL = 0x200000000000000; uint256 internal constant FLAG_DISABLE_KYBER_1 = 0x400000000000000; uint256 internal constant FLAG_DISABLE_KYBER_2 = 0x800000000000000; uint256 internal constant FLAG_DISABLE_KYBER_3 = 0x1000000000000000; uint256 internal constant FLAG_DISABLE_KYBER_4 = 0x2000000000000000; uint256 internal constant FLAG_ENABLE_CHI_BURN_BY_ORIGIN = 0x4000000000000000; } contract IOneSplit is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount); } contract IOneSplitMulti is IOneSplit { function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ); function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: contracts/interface/IUniswapExchange.sol pragma solidity ^0.5.0; interface IUniswapExchange { function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought); function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought); function ethToTokenSwapInput(uint256 minTokens, uint256 deadline) external payable returns (uint256 tokensBought); function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); } // File: contracts/interface/IUniswapFactory.sol pragma solidity ^0.5.0; interface IUniswapFactory { function getExchange(IERC20 token) external view returns (IUniswapExchange exchange); } // File: contracts/interface/IKyberNetworkContract.sol pragma solidity ^0.5.0; interface IKyberNetworkContract { function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless) external view returns (address reserve, uint256 rate); } // File: contracts/interface/IKyberNetworkProxy.sol pragma solidity ^0.5.0; interface IKyberNetworkProxy { function getExpectedRateAfterFee( IERC20 src, IERC20 dest, uint256 srcQty, uint256 platformFeeBps, bytes calldata hint ) external view returns (uint256 expectedRate); function tradeWithHintAndFee( IERC20 src, uint256 srcAmount, IERC20 dest, address payable destAddress, uint256 maxDestAmount, uint256 minConversionRate, address payable platformWallet, uint256 platformFeeBps, bytes calldata hint ) external payable returns (uint256 destAmount); function kyberNetworkContract() external view returns (IKyberNetworkContract); // TODO: Limit usage by tx.gasPrice // function maxGasPrice() external view returns (uint256); // TODO: Limit usage by user cap // function getUserCapInWei(address user) external view returns (uint256); // function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256); } // File: contracts/interface/IKyberStorage.sol pragma solidity ^0.5.0; interface IKyberStorage { function getReserveIdsPerTokenSrc( IERC20 token ) external view returns (bytes32[] memory); } // File: contracts/interface/IKyberHintHandler.sol pragma solidity ^0.5.0; interface IKyberHintHandler { enum TradeType { BestOfAll, MaskIn, MaskOut, Split } function buildTokenToEthHint( IERC20 tokenSrc, TradeType tokenToEthType, bytes32[] calldata tokenToEthReserveIds, uint256[] calldata tokenToEthSplits ) external view returns (bytes memory hint); function buildEthToTokenHint( IERC20 tokenDest, TradeType ethToTokenType, bytes32[] calldata ethToTokenReserveIds, uint256[] calldata ethToTokenSplits ) external view returns (bytes memory hint); } // File: contracts/interface/IBancorNetwork.sol pragma solidity ^0.5.0; interface IBancorNetwork { function getReturnByPath(address[] calldata path, uint256 amount) external view returns (uint256 returnAmount, uint256 conversionFee); function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn) external returns (uint256); function convert(address[] calldata path, uint256 amount, uint256 minReturn) external payable returns (uint256); } // File: contracts/interface/IBancorContractRegistry.sol pragma solidity ^0.5.0; contract IBancorContractRegistry { function addressOf(bytes32 contractName) external view returns (address); } // File: contracts/interface/IBancorNetworkPathFinder.sol pragma solidity ^0.5.0; interface IBancorNetworkPathFinder { function generatePath(IERC20 sourceToken, IERC20 targetToken) external view returns (address[] memory); } // File: contracts/interface/IBancorConverterRegistry.sol pragma solidity ^0.5.0; interface IBancorConverterRegistry { function getConvertibleTokenSmartTokenCount(IERC20 convertibleToken) external view returns(uint256); function getConvertibleTokenSmartTokens(IERC20 convertibleToken) external view returns(address[] memory); function getConvertibleTokenSmartToken(IERC20 convertibleToken, uint256 index) external view returns(address); function isConvertibleTokenSmartToken(IERC20 convertibleToken, address value) external view returns(bool); } // File: contracts/interface/IBancorEtherToken.sol pragma solidity ^0.5.0; contract IBancorEtherToken is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/IBancorFinder.sol pragma solidity ^0.5.0; interface IBancorFinder { function buildBancorPath( IERC20 fromToken, IERC20 destToken ) external view returns(address[] memory path); } // File: contracts/interface/IOasisExchange.sol pragma solidity ^0.5.0; interface IOasisExchange { function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt) external view returns (uint256 fillAmt); function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount) external returns (uint256 fillAmt); } // File: contracts/interface/IWETH.sol pragma solidity ^0.5.0; contract IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; } // File: contracts/interface/ICurve.sol pragma solidity ^0.5.0; interface ICurve { // solium-disable-next-line mixedcase function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy); // solium-disable-next-line mixedcase function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external; // solium-disable-next-line mixedcase function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external; } contract ICurveRegistry { function get_pool_info(address pool) external view returns( uint256[8] memory balances, uint256[8] memory underlying_balances, uint256[8] memory decimals, uint256[8] memory underlying_decimals, address lp_token, uint256 A, uint256 fee ); } contract ICurveCalculator { function get_dy( int128 nCoins, uint256[8] calldata balances, uint256 amp, uint256 fee, uint256[8] calldata rates, uint256[8] calldata precisions, bool underlying, int128 i, int128 j, uint256[100] calldata dx ) external view returns(uint256[100] memory dy); } // File: contracts/interface/IChai.sol pragma solidity ^0.5.0; interface IPot { function dsr() external view returns (uint256); function chi() external view returns (uint256); function rho() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } contract IChai is IERC20 { function POT() public view returns (IPot); function join(address dst, uint256 wad) external; function exit(address src, uint256 wad) external; } library ChaiHelper { IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7); uint256 private constant RAY = 10**27; function _mul(uint256 x, uint256 y) private pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, y) / RAY; } function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) { // always rounds down z = _mul(x, RAY) / y; } function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) { // solium-disable-next-line security/no-inline-assembly assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } function potDrip() private view returns (uint256) { return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi()); } function chaiPrice(IChai chai) internal view returns(uint256) { return chaiToDai(chai, 1e18); } function daiToChai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rdiv(amount, chi); } function chaiToDai( IChai /*chai*/, uint256 amount ) internal view returns (uint256) { uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi(); return _rmul(chi, amount); } } // File: contracts/interface/ICompound.sol pragma solidity ^0.5.0; contract ICompound { function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa); } contract ICompoundToken is IERC20 { function underlying() external view returns (address); function exchangeRateStored() external view returns (uint256); function mint(uint256 mintAmount) external returns (uint256); function redeem(uint256 redeemTokens) external returns (uint256); } contract ICompoundEther is IERC20 { function mint() external payable; function redeem(uint256 redeemTokens) external returns (uint256); } // File: contracts/interface/ICompoundRegistry.sol pragma solidity ^0.5.0; contract ICompoundRegistry { function tokenByCToken(ICompoundToken cToken) external view returns(IERC20); function cTokenByToken(IERC20 token) external view returns(ICompoundToken); } // File: contracts/interface/IAaveToken.sol pragma solidity ^0.5.0; contract IAaveToken is IERC20 { function underlyingAssetAddress() external view returns (IERC20); function redeem(uint256 amount) external; } interface IAaveLendingPool { function core() external view returns (address); function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable; } // File: contracts/interface/IAaveRegistry.sol pragma solidity ^0.5.0; contract IAaveRegistry { function tokenByAToken(IAaveToken aToken) external view returns(IERC20); function aTokenByToken(IERC20 token) external view returns(IAaveToken); } // File: contracts/interface/IMooniswap.sol pragma solidity ^0.5.0; interface IMooniswapRegistry { function target() external view returns(IMooniswap); } interface IMooniswap { function getReturn( IERC20 fromToken, IERC20 destToken, uint256 amount ) external view returns(uint256 returnAmount); function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn ) external payable returns(uint256 returnAmount); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.5; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: contracts/UniversalERC20.sol pragma solidity ^0.5.0; library UniversalERC20 { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000); IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) { if (amount == 0) { return true; } if (isETH(token)) { address(uint160(to)).transfer(amount); } else { token.safeTransfer(to, amount); return true; } } function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()"); if (to != address(this)) { address(uint160(to)).transfer(amount); } if (msg.value > amount) { msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(from, to, amount); } } function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal { if (amount == 0) { return; } if (isETH(token)) { if (msg.value > amount) { // Return remainder if exist msg.sender.transfer(msg.value.sub(amount)); } } else { token.safeTransferFrom(msg.sender, address(this), amount); } } function universalApprove(IERC20 token, address to, uint256 amount) internal { if (!isETH(token)) { if (amount == 0) { token.safeApprove(to, 0); return; } uint256 allowance = token.allowance(address(this), to); if (allowance < amount) { if (allowance > 0) { token.safeApprove(to, 0); } token.safeApprove(to, amount); } } } function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) { if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); } } function universalDecimals(IERC20 token) internal view returns (uint256) { if (isETH(token)) { return 18; } (bool success, bytes memory data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("decimals()") ); if (!success || data.length == 0) { (success, data) = address(token).staticcall.gas(10000)( abi.encodeWithSignature("DECIMALS()") ); } return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18; } function isETH(IERC20 token) internal pure returns(bool) { return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS)); } function notExist(IERC20 token) internal pure returns(bool) { return (address(token) == address(-1)); } } // File: contracts/interface/IUniswapV2Exchange.sol pragma solidity ^0.5.0; interface IUniswapV2Exchange { function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; } library UniswapV2ExchangeLib { using SafeMath for uint256; using UniversalERC20 for IERC20; function getReturn( IUniswapV2Exchange exchange, IERC20 fromToken, IERC20 destToken, uint amountIn ) internal view returns (uint256) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = destToken.universalBalanceOf(address(exchange)); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); return (denominator == 0) ? 0 : numerator.div(denominator); } } // File: contracts/interface/IUniswapV2Factory.sol pragma solidity ^0.5.0; interface IUniswapV2Factory { function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair); } // File: contracts/interface/IDForceSwap.sol pragma solidity ^0.5.0; interface IDForceSwap { function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256); function swap(IERC20 input, IERC20 output, uint256 amount) external; } // File: contracts/interface/IShell.sol pragma solidity ^0.5.0; interface IShell { function viewOriginTrade( address origin, address target, uint256 originAmount ) external view returns (uint256); function swapByOrigin( address origin, address target, uint256 originAmount, uint256 minTargetAmount, uint256 deadline ) external returns (uint256); } // File: contracts/interface/IMStable.sol pragma solidity ^0.5.0; contract IMStable is IERC20 { function getSwapOutput( IERC20 _input, IERC20 _output, uint256 _quantity ) external view returns (bool, string memory, uint256 output); function swap( IERC20 _input, IERC20 _output, uint256 _quantity, address _recipient ) external returns (uint256 output); function redeem( IERC20 _basset, uint256 _bassetQuantity ) external returns (uint256 massetRedeemed); } interface IMassetRedemptionValidator { function getRedeemValidity( IERC20 _mAsset, uint256 _mAssetQuantity, IERC20 _outputBasset ) external view returns (bool, string memory, uint256 output); } // File: contracts/interface/IBalancerRegistry.sol pragma solidity ^0.5.0; interface IBalancerPool { function swapExactAmountIn( IERC20 tokenIn, uint256 tokenAmountIn, IERC20 tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256 tokenAmountOut, uint256 spotPriceAfter); } pragma solidity ^0.5.0; interface IBalancerRegistry { event PoolAdded( address indexed pool ); event PoolTokenPairAdded( address indexed pool, address indexed fromToken, address indexed destToken ); event IndicesUpdated( address indexed fromToken, address indexed destToken, bytes32 oldIndices, bytes32 newIndices ); // Get info about pool pair for 1 SLOAD function getPairInfo(address pool, address fromToken, address destToken) external view returns(uint256 weight1, uint256 weight2, uint256 swapFee); // Pools function checkAddedPools(address pool) external view returns(bool); function getAddedPoolsLength() external view returns(uint256); function getAddedPools() external view returns(address[] memory); function getAddedPoolsWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Tokens function getAllTokensLength() external view returns(uint256); function getAllTokens() external view returns(address[] memory); function getAllTokensWithLimit(uint256 offset, uint256 limit) external view returns(address[] memory result); // Pairs function getPoolsLength(address fromToken, address destToken) external view returns(uint256); function getPools(address fromToken, address destToken) external view returns(address[] memory); function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit) external view returns(address[] memory result); function getBestPools(address fromToken, address destToken) external view returns(address[] memory pools); function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit) external view returns(address[] memory pools); // Get swap rates function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount) external view returns(uint256); function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts) external view returns(uint256[] memory result); // Add and update registry function addPool(address pool) external returns(uint256 listed); function addPools(address[] calldata pools) external returns(uint256[] memory listed); function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external; } // File: contracts/OneSplitBase.sol pragma solidity ^0.5.0; contract IOneSplitView is IOneSplitConsts { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns(bool) { return (flags & flag) != 0; } } contract OneSplitRoot is IOneSplitView { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20; using UniversalERC20 for IWETH; using UniswapV2ExchangeLib for IUniswapV2Exchange; using ChaiHelper for IChai; uint256 constant internal DEXES_COUNT = 31; IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315); IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215); IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376); IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53); IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51); IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1); IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D); IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847); IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380); IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6); IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e); IKyberStorage constant internal kyberStorage = IKyberStorage(0xC8fb12402cB16970F3C5F4b48Ff68Eb9D1289301); IKyberHintHandler constant internal kyberHintHandler = IKyberHintHandler(0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C); IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95); IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4); IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861); //IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518); IBancorFinder constant internal bancorFinder = IBancorFinder(0x2B344e14dc2641D11D338C053C908c7A7D4c30B9); IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D); ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56); ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C); ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51); ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27); ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD); ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763); ICurve constant internal curveRenBTC = ICurve(0x93054188d876f558f4a66B2EF1d97d16eDf0895B); ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E); ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714); IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D); IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119); ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5); IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0x7079E8517594e5b21d2B9a0D17cb33F5FE2bca70); IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2); IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5); IMassetRedemptionValidator constant internal musd_helper = IMassetRedemptionValidator(0x4c5e03065bC52cCe84F3ac94DF14bbAC27eac89b); IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982); ICurveCalculator constant internal curveCalculator = ICurveCalculator(0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E); ICurveRegistry constant internal curveRegistry = ICurveRegistry(0x7002B727Ef8F5571Cb5F9D70D13DBEEb4dFAe9d1); ICompoundRegistry constant internal compoundRegistry = ICompoundRegistry(0xF451Dbd7Ba14BFa7B1B78A766D3Ed438F79EE1D1); IAaveRegistry constant internal aaveRegistry = IAaveRegistry(0xEd8b133B7B88366E01Bb9E38305Ab11c26521494); int256 internal constant VERY_NEGATIVE_VALUE = -1e72; function _findBestDistribution( uint256 s, // parts int256[][] memory amounts // exchangesReturns ) internal pure returns( int256 returnAmount, uint256[] memory distribution ) { uint256 n = amounts.length; int256[][] memory answer = new int256[][](n); // int[n][s+1] uint256[][] memory parent = new uint256[][](n); // int[n][s+1] for (uint i = 0; i < n; i++) { answer[i] = new int256[](s + 1); parent[i] = new uint256[](s + 1); } for (uint j = 0; j <= s; j++) { answer[0][j] = amounts[0][j]; for (uint i = 1; i < n; i++) { answer[i][j] = -1e72; } parent[0][j] = 0; } for (uint i = 1; i < n; i++) { for (uint j = 0; j <= s; j++) { answer[i][j] = answer[i - 1][j]; parent[i][j] = j; for (uint k = 1; k <= j; k++) { if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) { answer[i][j] = answer[i - 1][j - k] + amounts[i][k]; parent[i][j] = j - k; } } } } distribution = new uint256[](DEXES_COUNT); uint256 partsLeft = s; for (uint curExchange = n - 1; partsLeft > 0; curExchange--) { distribution[curExchange] = partsLeft - parent[curExchange][partsLeft]; partsLeft = parent[curExchange][partsLeft]; } returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s]; } function _kyberReserveIdByTokens( IERC20 fromToken, IERC20 destToken ) internal view returns(bytes32) { if (!fromToken.isETH() && !destToken.isETH()) { return 0; } bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc( fromToken.isETH() ? destToken : fromToken ); for (uint i = 0; i < reserveIds.length; i++) { if ((uint256(reserveIds[i]) >> 248) != 0xBB && // Bridge reserveIds[i] != 0xff4b796265722046707200000000000000000000000000000000000000000000 && // Reserve 1 reserveIds[i] != 0xffabcd0000000000000000000000000000000000000000000000000000000000 && // Reserve 2 reserveIds[i] != 0xff4f6e65426974205175616e7400000000000000000000000000000000000000) // Reserve 3 { return reserveIds[i]; } } return 0; } function _scaleDestTokenEthPriceTimesGasPrice( IERC20 fromToken, IERC20 destToken, uint256 destTokenEthPriceTimesGasPrice ) internal view returns(uint256) { if (fromToken == destToken) { return destTokenEthPriceTimesGasPrice; } uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 0.01 ether); uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 0.01 ether); if (div > 0) { return destTokenEthPriceTimesGasPrice.mul(mul).div(div); } return 0; } function _cheapGetPrice( IERC20 fromToken, IERC20 destToken, uint256 amount ) internal view returns(uint256 returnAmount) { (returnAmount,,) = this.getExpectedReturnWithGas( fromToken, destToken, amount, 1, FLAG_DISABLE_SPLIT_RECALCULATION | FLAG_DISABLE_ALL_SPLIT_SOURCES | FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP, 0 ); } function _linearInterpolation( uint256 value, uint256 parts ) internal pure returns(uint256[] memory rets) { rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) { return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB); } } contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = this.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _getExpectedReturnRespectingGasFloor( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } contract OneSplitView is IOneSplitView, OneSplitRoot { function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT); if (fromToken == destToken) { return (amount, 0, distribution); } function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags); int256[][] memory matrix = new int256[][](DEXES_COUNT); uint256[DEXES_COUNT] memory gases; bool atLeastOnePositive = false; for (uint i = 0; i < DEXES_COUNT; i++) { uint256[] memory rets; (rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags); // Prepend zero and sub gas int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18)); matrix[i] = new int256[](parts + 1); for (uint j = 0; j < parts; j++) { matrix[i][j + 1] = int256(rets[j]) - gas; atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0); } } if (!atLeastOnePositive) { for (uint i = 0; i < DEXES_COUNT; i++) { for (uint j = 1; j < parts + 1; j++) { if (matrix[i][j] == 0) { matrix[i][j] = VERY_NEGATIVE_VALUE; } } } } (, distribution) = _findBestDistribution(parts, matrix); (returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution( Args({ fromToken: fromToken, destToken: destToken, amount: amount, parts: parts, flags: flags, destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice, distribution: distribution, matrix: matrix, gases: gases, reserves: reserves }) ); return (returnAmount, estimateGasAmount, distribution); } struct Args { IERC20 fromToken; IERC20 destToken; uint256 amount; uint256 parts; uint256 flags; uint256 destTokenEthPriceTimesGasPrice; uint256[] distribution; int256[][] matrix; uint256[DEXES_COUNT] gases; function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] reserves; } function _getReturnAndGasByDistribution( Args memory args ) internal view returns(uint256 returnAmount, uint256 estimateGasAmount) { bool[DEXES_COUNT] memory exact = [ true, // "Uniswap", false, // "Kyber", false, // "Bancor", false, // "Oasis", true, // "Curve Compound", true, // "Curve USDT", true, // "Curve Y", true, // "Curve Binance", true, // "Curve Synthetix", true, // "Uniswap Compound", true, // "Uniswap CHAI", true, // "Uniswap Aave", false, // "Mooniswap", true, // "Uniswap V2", true, // "Uniswap V2 (ETH)", true, // "Uniswap V2 (DAI)", true, // "Uniswap V2 (USDC)", true, // "Curve Pax", true, // "Curve RenBTC", true, // "Curve tBTC", true, // "Dforce XSwap", false, // "Shell", true, // "mStable", true, // "Curve sBTC" true, // "Balancer 1" true, // "Balancer 2" true, // "Balancer 3" true, // "Kyber 1" true, // "Kyber 2" true, // "Kyber 3" true // "Kyber 4" ]; for (uint i = 0; i < DEXES_COUNT; i++) { if (args.distribution[i] > 0) { if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add(uint256( (value == VERY_NEGATIVE_VALUE ? 0 : value) + int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18)) )); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves(uint256 flags) internal pure returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory) { bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES); return [ invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap, _calculateNoReturn, // invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber, invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor, invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai, invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave, invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI, invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC, invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap, invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell, invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD, invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2, invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_1) ? _calculateNoReturn : calculateKyber1, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_2) ? _calculateNoReturn : calculateKyber2, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_3) ? _calculateNoReturn : calculateKyber3, invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_4) ? _calculateNoReturn : calculateKyber4 ]; } function _calculateNoGas( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*parts*/, uint256 /*destTokenEthPriceTimesGasPrice*/, uint256 /*flags*/, uint256 /*destTokenEthPrice*/ ) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) { this; } // View Helpers function _calculateBalancer( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/, uint256 poolIndex ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (poolIndex >= pools.length) { return (rets, 0); } (bool success, bytes memory result) = address(balancerRegistry).staticcall( abi.encodeWithSelector( balancerRegistry.getPoolReturns.selector, pools[poolIndex], address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), _linearInterpolation(amount, parts) ) ); if (!success || result.length == 0) { return (rets, 0); } return ( abi.decode(result, (uint256[])), 100_000 ); } function calculateBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 0 ); } function calculateBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 1 ); } function calculateBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateBalancer( fromToken, destToken, amount, parts, flags, 2 ); } function calculateMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](parts); if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) || (destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd)) { return (rets, 0); } for (uint i = 1; i <= parts; i *= 2) { (bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector( musd.getSwapOutput.selector, fromToken, destToken, amount.mul(parts.div(i)).div(parts) )); if (success && data.length > 0) { (,, uint256 maxRet) = abi.decode(data, (bool,string,uint256)); if (maxRet > 0) { for (uint j = 0; j < parts.div(i); j++) { rets[j] = maxRet.mul(j + 1).div(parts.div(i)); } break; } } } return ( rets, 700_000 ); } function _getCurvePoolInfo( ICurve curve, bool haveUnderlying ) internal view returns( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) { uint256[8] memory underlying_balances; uint256[8] memory decimals; uint256[8] memory underlying_decimals; ( balances, underlying_balances, decimals, underlying_decimals, /*address lp_token*/, amp, fee ) = curveRegistry.get_pool_info(address(curve)); for (uint k = 0; k < 8 && balances[k] > 0; k++) { precisions[k] = 10 ** (18 - (haveUnderlying ? underlying_decimals : decimals)[k]); if (haveUnderlying) { rates[k] = underlying_balances[k].mul(1e18).div(balances[k]); } else { rates[k] = 1e18; } } } function _calculateCurveSelector( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, ICurve curve, bool haveUnderlying, IERC20[] memory tokens ) internal view returns(uint256[] memory rets) { rets = new uint256[](parts); int128 i = 0; int128 j = 0; for (uint t = 0; t < tokens.length; t++) { if (fromToken == tokens[t]) { i = int128(t + 1); } if (destToken == tokens[t]) { j = int128(t + 1); } } if (i == 0 || j == 0) { return rets; } bytes memory data = abi.encodePacked( uint256(haveUnderlying ? 1 : 0), uint256(i - 1), uint256(j - 1), _linearInterpolation100(amount, parts) ); ( uint256[8] memory balances, uint256[8] memory precisions, uint256[8] memory rates, uint256 amp, uint256 fee ) = _getCurvePoolInfo(curve, haveUnderlying); bool success; (success, data) = address(curveCalculator).staticcall( abi.encodePacked( abi.encodeWithSelector( curveCalculator.get_dy.selector, tokens.length, balances, amp, fee, rates, precisions ), data ) ); if (!success || data.length == 0) { return rets; } uint256[100] memory dy = abi.decode(data, (uint256[100])); for (uint t = 0; t < parts; t++) { rets[t] = dy[t]; } } function _linearInterpolation100( uint256 value, uint256 parts ) internal pure returns(uint256[100] memory rets) { for (uint i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function calculateCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = dai; tokens[1] = usdc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveCompound, true, tokens ), 720_000); } function calculateCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveUSDT, true, tokens ), 720_000); } function calculateCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = tusd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveY, true, tokens ), 1_400_000); } function calculateCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = busd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveBinance, true, tokens ), 1_400_000); } function calculateCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = susd; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSynthetix, true, tokens ), 200_000); } function calculateCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](4); tokens[0] = dai; tokens[1] = usdc; tokens[2] = usdt; tokens[3] = pax; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curvePAX, true, tokens ), 1_000_000); } function calculateCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](2); tokens[0] = renbtc; tokens[1] = wbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveRenBTC, false, tokens ), 130_000); } function calculateCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = tbtc; tokens[1] = wbtc; tokens[2] = hbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveTBTC, false, tokens ), 145_000); } function calculateCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20[] memory tokens = new IERC20[](3); tokens[0] = renbtc; tokens[1] = wbtc; tokens[2] = sbtc; return (_calculateCurveSelector( fromToken, destToken, amount, parts, curveSBTC, false, tokens ), 150_000); } function calculateShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector( shell.viewOriginTrade.selector, fromToken, destToken, amount )); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 300_000); } function calculateDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { (bool success, bytes memory data) = address(dforceSwap).staticcall( abi.encodeWithSelector( dforceSwap.getAmountByInput.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); uint256 available = destToken.universalBalanceOf(address(dforceSwap)); if (maxRet > available) { return (new uint256[](parts), 0); } return (_linearInterpolation(maxRet, parts), 160_000); } function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) { if (amount == 0) { return 0; } return amount.mul(toBalance).mul(997).div( fromBalance.mul(1000).add(amount.mul(997)) ); } function _calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = amounts; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange)); uint256 fromEtherBalance = address(fromExchange).balance; for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange == IUniswapExchange(0)) { return (new uint256[](rets.length), 0); } uint256 toEtherBalance = address(toExchange).balance; uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange)); for (uint i = 0; i < rets.length; i++) { rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]); } } return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000); } function calculateUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswap( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function _calculateUniswapWrapped( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 midTokenPrice, uint256 flags, uint256 gas1, uint256 gas2 ) internal view returns(uint256[] memory rets, uint256 gas) { if (!fromToken.isETH() && destToken.isETH()) { (rets, gas) = _calculateUniswap( midToken, destToken, _linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts), flags ); return (rets, gas + gas1); } else if (fromToken.isETH() && !destToken.isETH()) { (rets, gas) = _calculateUniswap( fromToken, midToken, _linearInterpolation(amount, parts), flags ); for (uint i = 0; i < parts; i++) { rets[i] = rets[i].mul(midTokenPrice).div(1e18); } return (rets, gas + gas2); } return (new uint256[](parts), 0); } function calculateUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { ICompoundToken midToken = compoundRegistry.cTokenByToken(midPreToken); if (midToken != ICompoundToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, midToken.exchangeRateStored(), flags, 200_000, 200_000 ); } } return (new uint256[](parts), 0); } function calculateUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai && destToken.isETH() || fromToken.isETH() && destToken == dai) { return _calculateUniswapWrapped( fromToken, chai, destToken, amount, parts, chai.chaiPrice(), flags, 180_000, 160_000 ); } return (new uint256[](parts), 0); } function calculateUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { IERC20 midPreToken; if (!fromToken.isETH() && destToken.isETH()) { midPreToken = fromToken; } else if (!destToken.isETH() && fromToken.isETH()) { midPreToken = destToken; } if (!midPreToken.isETH()) { IAaveToken midToken = aaveRegistry.aTokenByToken(midPreToken); if (midToken != IAaveToken(0)) { return _calculateUniswapWrapped( fromToken, midToken, destToken, amount, parts, 1e18, flags, 310_000, 670_000 ); } } return (new uint256[](parts), 0); } function calculateKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 // 0x63825c174ab367968EC60f061753D3bbD36A0D8F ); } function calculateKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 // 0x7a3370075a54B187d7bD5DceBf0ff2B5552d4F7D ); } function calculateKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateKyber( fromToken, destToken, amount, parts, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 // 0x4f32BbE8dFc9efD54345Fc936f9fEF1048746fCF ); } function calculateKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { bytes32 reserveId = _kyberReserveIdByTokens(fromToken, destToken); if (reserveId == 0) { return (new uint256[](parts), 0); } return _calculateKyber( fromToken, destToken, amount, parts, flags, reserveId ); } function _kyberGetRate( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags, bytes memory hint ) private view returns(uint256) { (, bytes memory data) = address(kyberNetworkProxy).staticcall( abi.encodeWithSelector( kyberNetworkProxy.getExpectedRateAfterFee.selector, fromToken, destToken, amount, flags.check(1 << 255) ? 10 : 0, hint ) ); return (data.length == 32) ? abi.decode(data, (uint256)) : 0; } function _calculateKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, bytes32 reserveId ) internal view returns(uint256[] memory rets, uint256 gas) { bytes memory fromHint; bytes memory destHint; { bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; (bool success, bytes memory data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildTokenToEthHint.selector, fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); fromHint = success ? abi.decode(data, (bytes)) : bytes(""); (success, data) = address(kyberHintHandler).staticcall( abi.encodeWithSelector( kyberHintHandler.buildEthToTokenHint.selector, destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ) ); destHint = success ? abi.decode(data, (bytes)) : bytes(""); } uint256 fromTokenDecimals = 10 ** IERC20(fromToken).universalDecimals(); uint256 destTokenDecimals = 10 ** IERC20(destToken).universalDecimals(); rets = new uint256[](parts); for (uint i = 0; i < parts; i++) { if (i > 0 && rets[i - 1] == 0) { break; } rets[i] = amount.mul(i + 1).div(parts); if (!fromToken.isETH()) { if (fromHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( fromToken, ETH_ADDRESS, rets[i], flags, fromHint ); rets[i] = rate.mul(rets[i]).div(fromTokenDecimals); } if (!destToken.isETH() && rets[i] > 0) { if (destHint.length == 0) { rets[i] = 0; break; } uint256 rate = _kyberGetRate( ETH_ADDRESS, destToken, rets[i], flags.check(1 << 255) ? 10 : 0, destHint ); rets[i] = rate.mul(rets[i]).mul(destTokenDecimals).div(1e36); } } return (rets, 100_000); } function calculateBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorFinder.buildBancorPath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)( abi.encodeWithSelector( bancorNetwork.getReturnByPath.selector, path, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { (uint256 ret,) = abi.decode(data, (uint256,uint256)); rets[i] = ret; } } return (rets, path.length.mul(150_000)); } function calculateOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); for (uint i = 0; i < parts; i++) { (bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)( abi.encodeWithSelector( oasisExchange.getBuyAmount.selector, destToken.isETH() ? weth : destToken, fromToken.isETH() ? weth : fromToken, rets[i] ) ); if (!success || data.length == 0) { for (; i < parts; i++) { rets[i] = 0; } break; } else { rets[i] = abi.decode(data, (uint256)); } } return (rets, 500_000); } function calculateMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { IMooniswap mooniswap = mooniswapRegistry.target(); (bool success, bytes memory data) = address(mooniswap).staticcall.gas(1000000)( abi.encodeWithSelector( mooniswap.getReturn.selector, fromToken, destToken, amount ) ); if (!success || data.length == 0) { return (new uint256[](parts), 0); } uint256 maxRet = abi.decode(data, (uint256)); return (_linearInterpolation(maxRet, parts), 1_000_000); } function calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { return _calculateUniswapV2( fromToken, destToken, _linearInterpolation(amount, parts), flags ); } function calculateUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, weth, destToken, amount, parts, flags ); } function calculateUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == dai || destToken == dai) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, dai, destToken, amount, parts, flags ); } function calculateUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { if (fromToken == usdc || destToken == usdc) { return (new uint256[](parts), 0); } return _calculateUniswapV2OverMidToken( fromToken, usdc, destToken, amount, parts, flags ); } function _calculateUniswapV2( IERC20 fromToken, IERC20 destToken, uint256[] memory amounts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 destTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal); if (exchange != IUniswapV2Exchange(0)) { uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange)); uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange)); for (uint i = 0; i < amounts.length; i++) { rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]); } return (rets, 50_000); } } function _calculateUniswapV2OverMidToken( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) internal view returns(uint256[] memory rets, uint256 gas) { rets = _linearInterpolation(amount, parts); uint256 gas1; uint256 gas2; (rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags); (rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags); return (rets, gas1 + gas2); } function _calculateNoReturn( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 parts, uint256 /*flags*/ ) internal view returns(uint256[] memory rets, uint256 gas) { this; return (new uint256[](parts), 0); } } contract OneSplitBaseWrap is IOneSplit, OneSplitRoot { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) internal { if (fromToken == destToken) { return; } _swapFloor( fromToken, destToken, amount, distribution, flags ); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 /*flags*/ // See constants in IOneSplit.sol ) internal; } contract OneSplit is IOneSplit, OneSplitRoot { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplitView) public { oneSplitView = _oneSplitView; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags // See constants in IOneSplit.sol ) public payable returns(uint256 returnAmount) { if (fromToken == destToken) { return amount; } function(IERC20,IERC20,uint256,uint256)[DEXES_COUNT] memory reserves = [ _swapOnUniswap, _swapOnNowhere, _swapOnBancor, _swapOnOasis, _swapOnCurveCompound, _swapOnCurveUSDT, _swapOnCurveY, _swapOnCurveBinance, _swapOnCurveSynthetix, _swapOnUniswapCompound, _swapOnUniswapChai, _swapOnUniswapAave, _swapOnMooniswap, _swapOnUniswapV2, _swapOnUniswapV2ETH, _swapOnUniswapV2DAI, _swapOnUniswapV2USDC, _swapOnCurvePAX, _swapOnCurveRenBTC, _swapOnCurveTBTC, _swapOnDforceSwap, _swapOnShell, _swapOnMStableMUSD, _swapOnCurveSBTC, _swapOnBalancer1, _swapOnBalancer2, _swapOnBalancer3, _swapOnKyber1, _swapOnKyber2, _swapOnKyber3, _swapOnKyber4 ]; require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size"); uint256 parts = 0; uint256 lastNonZeroIndex = 0; for (uint i = 0; i < distribution.length; i++) { if (distribution[i] > 0) { parts = parts.add(distribution[i]); lastNonZeroIndex = i; } } if (parts == 0) { if (fromToken.isETH()) { msg.sender.transfer(msg.value); return msg.value; } return amount; } fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); for (uint i = 0; i < distribution.length; i++) { if (distribution[i] == 0) { continue; } uint256 swapAmount = amount.mul(distribution[i]).div(parts); if (i == lastNonZeroIndex) { swapAmount = remainingAmount; } remainingAmount -= swapAmount; reserves[i](fromToken, destToken, swapAmount, flags); } returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: Return amount was not enough"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } // Swap helpers function _swapOnCurveCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveCompound), amount); curveCompound.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveUSDT( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveUSDT), amount); curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveY( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == tusd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == tusd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveY), amount); curveY.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveBinance( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == busd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == busd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveBinance), amount); curveBinance.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurveSynthetix( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == susd ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == susd ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveSynthetix), amount); curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnCurvePAX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0) + (fromToken == usdt ? 3 : 0) + (fromToken == pax ? 4 : 0); int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0) + (destToken == usdt ? 3 : 0) + (destToken == pax ? 4 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curvePAX), amount); curvePAX.exchange_underlying(i - 1, j - 1, amount, 0); } function _swapOnShell( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(shell), amount); shell.swapByOrigin( address(fromToken), address(destToken), amount, 0, now + 50 ); } function _swapOnMStableMUSD( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } function _swapOnCurveRenBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveRenBTC), amount); curveRenBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveTBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == tbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == hbtc ? 3 : 0); int128 j = (destToken == tbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == hbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveTBTC), amount); curveTBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnCurveSBTC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { int128 i = (fromToken == renbtc ? 1 : 0) + (fromToken == wbtc ? 2 : 0) + (fromToken == sbtc ? 3 : 0); int128 j = (destToken == renbtc ? 1 : 0) + (destToken == wbtc ? 2 : 0) + (destToken == sbtc ? 3 : 0); if (i == 0 || j == 0) { return; } fromToken.universalApprove(address(curveSBTC), amount); curveSBTC.exchange(i - 1, j - 1, amount, 0); } function _swapOnDforceSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { fromToken.universalApprove(address(dforceSwap), amount); dforceSwap.swap(fromToken, destToken, amount); } function _swapOnUniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { uint256 returnAmount = amount; if (!fromToken.isETH()) { IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken); if (fromExchange != IUniswapExchange(0)) { fromToken.universalApprove(address(fromExchange), returnAmount); returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now); } } if (!destToken.isETH()) { IUniswapExchange toExchange = uniswapFactory.getExchange(destToken); if (toExchange != IUniswapExchange(0)) { returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now); } } } function _swapOnUniswapCompound( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { ICompoundToken fromCompound = compoundRegistry.cTokenByToken(fromToken); fromToken.universalApprove(address(fromCompound), amount); fromCompound.mint(amount); _swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { ICompoundToken toCompound = compoundRegistry.cTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toCompound), amount, flags); toCompound.redeem(IERC20(toCompound).universalBalanceOf(address(this))); destToken.universalBalanceOf(address(this)); return; } } function _swapOnUniswapChai( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (fromToken == dai) { fromToken.universalApprove(address(chai), amount); chai.join(address(this), amount); _swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this)), flags); return; } if (destToken == dai) { _swapOnUniswap(fromToken, IERC20(chai), amount, flags); chai.exit(address(this), chai.balanceOf(address(this))); return; } } function _swapOnUniswapAave( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { if (!fromToken.isETH()) { IAaveToken fromAave = aaveRegistry.aTokenByToken(fromToken); fromToken.universalApprove(aave.core(), amount); aave.deposit(fromToken, amount, 1101); _swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this)), flags); return; } if (!destToken.isETH()) { IAaveToken toAave = aaveRegistry.aTokenByToken(destToken); _swapOnUniswap(fromToken, IERC20(toAave), amount, flags); toAave.redeem(toAave.balanceOf(address(this))); return; } } function _swapOnMooniswap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IMooniswap mooniswap = mooniswapRegistry.target(); fromToken.universalApprove(address(mooniswap), amount); mooniswap.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0 ); } function _swapOnNowhere( IERC20 /*fromToken*/, IERC20 /*destToken*/, uint256 /*amount*/, uint256 /*flags*/ ) internal { revert("This source was deprecated"); } function _swapOnKyber1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4b796265722046707200000000000000000000000000000000000000000000 ); } function _swapOnKyber2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xffabcd0000000000000000000000000000000000000000000000000000000000 ); } function _swapOnKyber3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, 0xff4f6e65426974205175616e7400000000000000000000000000000000000000 ); } function _swapOnKyber4( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnKyber( fromToken, destToken, amount, flags, _kyberReserveIdByTokens(fromToken, destToken) ); } function _swapOnKyber( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags, bytes32 reserveId ) internal { uint256 returnAmount = amount; uint256 bps = flags.check(1 << 255) ? 10 : 0; bytes32[] memory reserveIds = new bytes32[](1); reserveIds[0] = reserveId; if (!fromToken.isETH()) { bytes memory fromHint = kyberHintHandler.buildTokenToEthHint( fromToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); fromToken.universalApprove(address(kyberNetworkProxy), amount); returnAmount = kyberNetworkProxy.tradeWithHintAndFee( fromToken, returnAmount, ETH_ADDRESS, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, bps, fromHint ); } if (!destToken.isETH()) { bytes memory destHint = kyberHintHandler.buildEthToTokenHint( destToken, IKyberHintHandler.TradeType.MaskIn, reserveIds, new uint256[](0) ); returnAmount = kyberNetworkProxy.tradeWithHintAndFee.value(returnAmount)( ETH_ADDRESS, returnAmount, destToken, address(this), uint256(-1), 0, 0x4D37f28D2db99e8d35A6C725a5f1749A085850a3, bps, destHint ); } } function _swapOnBancor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork")); address[] memory path = bancorNetworkPathFinder.generatePath( fromToken.isETH() ? bancorEtherToken : fromToken, destToken.isETH() ? bancorEtherToken : destToken ); fromToken.universalApprove(address(bancorNetwork), amount); bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1); } function _swapOnOasis( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 approveToken = fromToken.isETH() ? weth : fromToken; approveToken.universalApprove(address(oasisExchange), amount); oasisExchange.sellAllAmount( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 1 ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2Internal( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/ ) internal returns(uint256 returnAmount) { if (fromToken.isETH()) { weth.deposit.value(amount)(); } IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken; IERC20 toTokenReal = destToken.isETH() ? weth : destToken; IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal); returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount); fromTokenReal.universalTransfer(address(exchange), amount); if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) { exchange.swap(0, returnAmount, address(this), ""); } else { exchange.swap(returnAmount, 0, address(this), ""); } if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnUniswapV2OverMid( IERC20 fromToken, IERC20 midToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( midToken, destToken, _swapOnUniswapV2Internal( fromToken, midToken, amount, flags ), flags ); } function _swapOnUniswapV2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2Internal( fromToken, destToken, amount, flags ); } function _swapOnUniswapV2ETH( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, weth, destToken, amount, flags ); } function _swapOnUniswapV2DAI( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, dai, destToken, amount, flags ); } function _swapOnUniswapV2USDC( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnUniswapV2OverMid( fromToken, usdc, destToken, amount, flags ); } function _swapOnBalancerX( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 /*flags*/, uint256 poolIndex ) internal { address[] memory pools = balancerRegistry.getBestPoolsWithLimit( address(fromToken.isETH() ? weth : fromToken), address(destToken.isETH() ? weth : destToken), poolIndex + 1 ); if (fromToken.isETH()) { weth.deposit.value(amount)(); } (fromToken.isETH() ? weth : fromToken).universalApprove(pools[poolIndex], amount); IBalancerPool(pools[poolIndex]).swapExactAmountIn( fromToken.isETH() ? weth : fromToken, amount, destToken.isETH() ? weth : destToken, 0, uint256(-1) ); if (destToken.isETH()) { weth.withdraw(weth.balanceOf(address(this))); } } function _swapOnBalancer1( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 0); } function _swapOnBalancer2( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 1); } function _swapOnBalancer3( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 flags ) internal { _swapOnBalancerX(fromToken, destToken, amount, flags, 2); } } // File: contracts/OneSplitCompound.sol pragma solidity ^0.5.0; contract OneSplitCompoundView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _compoundGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _compoundGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn( underlying, destToken, amount.mul(compoundRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18) ); return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitCompound is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _compoundSwap( fromToken, destToken, amount, distribution, flags ); } function _compoundSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) { IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken))); if (underlying != IERC20(0)) { ICompoundToken(address(fromToken)).redeem(amount); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return _compoundSwap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { cETH.mint.value(underlyingAmount)(); } else { underlying.universalApprove(address(destToken), underlyingAmount); ICompoundToken(address(destToken)).mint(underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IFulcrum.sol pragma solidity ^0.5.0; contract IFulcrumToken is IERC20 { function tokenPrice() external view returns (uint256); function loanTokenAddress() external view returns (address); function mintWithEther(address receiver) external payable returns (uint256 mintAmount); function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount); function burnToEther(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid); } // File: contracts/OneSplitFulcrum.sol pragma solidity ^0.5.0; contract OneSplitFulcrumBase { using UniversalERC20 for IERC20; function _isFulcrumToken(IERC20 token) internal view returns(IERC20) { if (token.isETH()) { return IERC20(-1); } (bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature( "name()" )); if (!success) { return IERC20(-1); } bool foundBZX = false; for (uint i = 0; i + 6 < data.length; i++) { if (data[i + 0] == "F" && data[i + 1] == "u" && data[i + 2] == "l" && data[i + 3] == "c" && data[i + 4] == "r" && data[i + 5] == "u" && data[i + 6] == "m") { foundBZX = true; break; } } if (!foundBZX) { return IERC20(-1); } (success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector( IFulcrumToken(address(token)).loanTokenAddress.selector )); if (!success) { return IERC20(-1); } return abi.decode(data, (IERC20)); } } contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _fulcrumGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _fulcrumGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn( underlying, destToken, amount.mul(fulcrumRate).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 381_000, distribution); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18) ); return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _fulcrumSwap( fromToken, destToken, amount, distribution, flags ); } function _fulcrumSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) { IERC20 underlying = _isFulcrumToken(fromToken); if (underlying != IERC20(-1)) { if (underlying.isETH()) { IFulcrumToken(address(fromToken)).burnToEther(address(this), amount); } else { IFulcrumToken(address(fromToken)).burn(address(this), amount); } uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); return super._swap( underlying, destToken, underlyingAmount, distribution, flags ); } underlying = _isFulcrumToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); if (underlying.isETH()) { IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this)); } else { underlying.universalApprove(address(destToken), underlyingAmount); IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitChai.sol pragma solidity ^0.5.0; contract OneSplitChaiView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, chai.chaiToDai(amount), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 197_000, distribution); } if (destToken == IERC20(chai)) { uint256 price = chai.chaiPrice(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(1e18).div(price) ); return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitChai is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) { if (fromToken == IERC20(chai)) { chai.exit(address(this), amount); return super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } if (destToken == IERC20(chai)) { super._swap( fromToken, dai, amount, distribution, flags ); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(chai), daiBalance); chai.join(address(this), daiBalance); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IBdai.sol pragma solidity ^0.5.0; contract IBdai is IERC20 { function join(uint256) external; function exit(uint256) external; } // File: contracts/OneSplitBdai.sol pragma solidity ^0.5.0; contract OneSplitBdaiBase { IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8); IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f); } contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 227_000, distribution); } if (destToken == IERC20(bdai)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) { if (fromToken == IERC20(bdai)) { bdai.exit(amount); uint256 btuBalance = btu.balanceOf(address(this)); if (btuBalance > 0) { (,uint256[] memory btuDistribution) = getExpectedReturn( btu, destToken, btuBalance, 1, flags ); _swap( btu, destToken, btuBalance, btuDistribution, flags ); } return super._swap( dai, destToken, amount, distribution, flags ); } if (destToken == IERC20(bdai)) { super._swap(fromToken, dai, amount, distribution, flags); uint256 daiBalance = dai.balanceOf(address(this)); dai.universalApprove(address(bdai), daiBalance); bdai.join(daiBalance); return; } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIearn.sol pragma solidity ^0.5.0; contract IIearn is IERC20 { function token() external view returns(IERC20); function calcPoolValueInToken() external view returns(uint256); function deposit(uint256 _amount) external; function withdraw(uint256 _shares) external; } // File: contracts/OneSplitIearn.sol pragma solidity ^0.5.0; contract OneSplitIearnBase { function _yTokens() internal pure returns(IIearn[13] memory) { return [ IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01), IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9), IIearn(0x73a052500105205d34Daf004eAb301916DA8190f), IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D), IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e), IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600), IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE), IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32), IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447), IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951), IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc), IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E), IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59) ]; } } contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _iearnGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _iearnGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { (returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn( yTokens[i].token(), destToken, amount .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 260_000, distribution); } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; IERC20 token = yTokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice .mul(yTokens[i].calcPoolValueInToken()) .div(yTokens[i].totalSupply()) ); return( returnAmount .mul(yTokens[i].totalSupply()) .div(yTokens[i].calcPoolValueInToken()), estimateGasAmount + 743_000, distribution ); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _iearnSwap( fromToken, destToken, amount, distribution, flags ); } function _iearnSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) { IIearn[13] memory yTokens = _yTokens(); for (uint i = 0; i < yTokens.length; i++) { if (fromToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); yTokens[i].withdraw(amount); _iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags); return; } } for (uint i = 0; i < yTokens.length; i++) { if (destToken == IERC20(yTokens[i])) { IERC20 underlying = yTokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(yTokens[i]), underlyingBalance); yTokens[i].deposit(underlyingBalance); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/interface/IIdle.sol pragma solidity ^0.5.0; contract IIdle is IERC20 { function token() external view returns (IERC20); function tokenPrice() external view returns (uint256); function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts) external returns (uint256 mintedTokens); function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts) external returns (uint256 redeemedTokens); } // File: contracts/OneSplitIdle.sol pragma solidity ^0.5.0; contract OneSplitIdleBase { function _idleTokens() internal pure returns(IIdle[8] memory) { // https://developers.idle.finance/contracts-and-codebase return [ // V3 IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934), IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6), IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D), IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB), IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C), IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B), // V2 IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD), IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991) ]; } } contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _idleGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _idleGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { (returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn( tokens[i].token(), destToken, amount.mul(tokens[i].tokenPrice()).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 2_400_000, distribution); } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice; uint256 _price = tokens[i].tokenPrice(); IERC20 token = tokens[i].token(); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, token, amount, parts, flags, _destTokenEthPriceTimesGasPrice.mul(_price).div(1e18) ); return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _idleSwap( fromToken, destToken, amount, distribution, flags ); } function _idleSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) { IIdle[8] memory tokens = _idleTokens(); for (uint i = 0; i < tokens.length; i++) { if (fromToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0)); _idleSwap(underlying, destToken, minted, distribution, flags); return; } } for (uint i = 0; i < tokens.length; i++) { if (destToken == IERC20(tokens[i])) { IERC20 underlying = tokens[i].token(); super._swap(fromToken, underlying, amount, distribution, flags); uint256 underlyingBalance = underlying.balanceOf(address(this)); underlying.universalApprove(address(tokens[i]), underlyingBalance); tokens[i].mintIdleToken(underlyingBalance, new uint256[](0)); return; } } } return super._swap(fromToken, destToken, amount, distribution, flags); } } // File: contracts/OneSplitAave.sol pragma solidity ^0.5.0; contract OneSplitAaveView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _aaveGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _aaveGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn( underlying, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 670_000, distribution); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 310_000, distribution); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitAave is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _aaveSwap( fromToken, destToken, amount, distribution, flags ); } function _aaveSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) { IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken))); if (underlying != IERC20(0)) { IAaveToken(address(fromToken)).redeem(amount); return _aaveSwap( underlying, destToken, amount, distribution, flags ); } underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken))); if (underlying != IERC20(0)) { super._swap( fromToken, underlying, amount, distribution, flags ); uint256 underlyingAmount = underlying.universalBalanceOf(address(this)); underlying.universalApprove(aave.core(), underlyingAmount); aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)( underlying.isETH() ? ETH_ADDRESS : underlying, underlyingAmount, 1101 ); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitWeth.sol pragma solidity ^0.5.0; contract OneSplitWethView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _wethGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _wethGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth || fromToken == bancorEtherToken) { return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice); } if (destToken == weth || destToken == bancorEtherToken) { return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWeth is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _wethSwap( fromToken, destToken, amount, distribution, flags ); } function _wethSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) { if (fromToken == weth) { weth.withdraw(weth.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (fromToken == bancorEtherToken) { bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this))); super._swap( ETH_ADDRESS, destToken, amount, distribution, flags ); return; } if (destToken == weth) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); weth.deposit.value(address(this).balance)(); return; } if (destToken == bancorEtherToken) { _wethSwap( fromToken, ETH_ADDRESS, amount, distribution, flags ); bancorEtherToken.deposit.value(address(this).balance)(); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplitMStable.sol pragma solidity ^0.5.0; contract OneSplitMStableView is OneSplitViewWrapBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, destToken); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { (,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, dai); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( dai, destToken, returnAmount, parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 300_000, distribution); } } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { (,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount); return (returnAmount, 300_000, new uint256[](DEXES_COUNT)); } else { IERC20 _destToken = destToken; (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, dai, amount, parts, flags, _scaleDestTokenEthPriceTimesGasPrice( _destToken, dai, destTokenEthPriceTimesGasPrice ) ); (,, returnAmount) = musd_helper.getRedeemValidity(dai, returnAmount, destToken); return (returnAmount, estimateGasAmount + 300_000, distribution); } } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitMStable is OneSplitBaseWrap { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) { if (fromToken == IERC20(musd)) { if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken); musd.redeem( destToken, result ); } else { (,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai); musd.redeem( dai, result ); super._swap( dai, destToken, dai.balanceOf(address(this)), distribution, flags ); } return; } if (destToken == IERC20(musd)) { if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) { fromToken.universalApprove(address(musd), amount); musd.swap( fromToken, destToken, amount, address(this) ); } else { super._swap( fromToken, dai, amount, distribution, flags ); musd.swap( dai, destToken, dai.balanceOf(address(this)), address(this) ); } return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/interface/IDMM.sol pragma solidity ^0.5.0; interface IDMMController { function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20); } contract IDMM is IERC20 { function getCurrentExchangeRate() public view returns(uint256); function mint(uint256 underlyingAmount) public returns(uint256); function redeem(uint256 amount) public returns(uint256); } // File: contracts/OneSplitDMM.sol pragma solidity ^0.5.0; contract OneSplitDMMBase { IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2); function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) { (bool success, bytes memory data) = address(_dmmController).staticcall( abi.encodeWithSelector( _dmmController.getUnderlyingTokenForDmm.selector, token ) ); if (!success || data.length == 0) { return IERC20(-1); } return abi.decode(data, (IERC20)); } function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) { (bool success, bytes memory data) = address(dmm).staticcall( abi.encodeWithSelector( dmm.getCurrentExchangeRate.selector ) ); if (!success || data.length == 0) { return 0; } return abi.decode(data, (uint256)); } } contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase { function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return _dmmGetExpectedReturn( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _dmmGetExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) private view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } IERC20 _fromToken = fromToken; (returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn( underlying, destToken, amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18), parts, flags, destTokenEthPriceTimesGasPrice ); return (returnAmount, estimateGasAmount + 295_000, distribution); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { if (underlying == weth) { underlying = ETH_ADDRESS; } uint256 price = _getDMMExchangeRate(IDMM(address(destToken))); (returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas( fromToken, underlying, amount, parts, flags, destTokenEthPriceTimesGasPrice.mul(price).div(1e18) ); return ( returnAmount.mul(1e18).div(price), estimateGasAmount + 430_000, distribution ); } } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase { function _swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { _dmmSwap( fromToken, destToken, amount, distribution, flags ); } function _dmmSwap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) private { if (fromToken == destToken) { return; } if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) { IERC20 underlying = _getDMMUnderlyingToken(fromToken); if (underlying != IERC20(-1)) { IDMM(address(fromToken)).redeem(amount); uint256 balance = underlying.universalBalanceOf(address(this)); if (underlying == weth) { weth.withdraw(balance); } _dmmSwap( (underlying == weth) ? ETH_ADDRESS : underlying, destToken, balance, distribution, flags ); } underlying = _getDMMUnderlyingToken(destToken); if (underlying != IERC20(-1)) { super._swap( fromToken, (underlying == weth) ? ETH_ADDRESS : underlying, amount, distribution, flags ); uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this)); if (underlying == weth) { weth.deposit.value(underlyingAmount); } underlying.universalApprove(address(destToken), underlyingAmount); IDMM(address(destToken)).mint(underlyingAmount); return; } } return super._swap( fromToken, destToken, amount, distribution, flags ); } } // File: contracts/OneSplit.sol pragma solidity ^0.5.0; contract OneSplitViewWrap is OneSplitViewWrapBase, OneSplitMStableView, OneSplitChaiView, OneSplitBdaiView, OneSplitAaveView, OneSplitFulcrumView, OneSplitCompoundView, OneSplitIearnView, OneSplitIdleView, OneSplitWethView, OneSplitDMMView { IOneSplitView public oneSplitView; constructor(IOneSplitView _oneSplit) public { oneSplitView = _oneSplit; } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { if (fromToken == destToken) { return (amount, 0, new uint256[](DEXES_COUNT)); } return super.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function _getExpectedReturnRespectingGasFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) internal view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } } contract OneSplitWrap is OneSplitBaseWrap, OneSplitMStable, OneSplitChai, OneSplitBdai, OneSplitAave, OneSplitFulcrum, OneSplitCompound, OneSplitIearn, OneSplitIdle, OneSplitWeth, OneSplitDMM { IOneSplitView public oneSplitView; IOneSplit public oneSplit; constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public { oneSplitView = _oneSplitView; oneSplit = _oneSplit; } function() external payable { // solium-disable-next-line security/no-tx-origin require(msg.sender != tx.origin); } function getExpectedReturn( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags ) public view returns( uint256 returnAmount, uint256[] memory distribution ) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view returns( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { return oneSplitView.getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice ); } function getExpectedReturnWithGasMulti( IERC20[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view returns( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ) { uint256[] memory dist; returnAmounts = new uint256[](tokens.length - 1); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } IERC20[] memory _tokens = tokens; ( returnAmounts[i - 1], amount, dist ) = getExpectedReturnWithGas( _tokens[i - 1], _tokens[i], (i == 1) ? amount : returnAmounts[i - 2], parts[i], flags[i], destTokenEthPriceTimesGasPrices[i] ); estimateGasAmount = estimateGasAmount.add(amount); if (distribution.length == 0) { distribution = new uint256[](dist.length); } for (uint j = 0; j < distribution.length; j++) { distribution[j] = distribution[j].add(dist[j] << (8 * (i - 1))); } } } function swap( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256 flags ) public payable returns(uint256 returnAmount) { fromToken.universalTransferFrom(msg.sender, address(this), amount); uint256 confirmed = fromToken.universalBalanceOf(address(this)); _swap(fromToken, destToken, confirmed, distribution, flags); returnAmount = destToken.universalBalanceOf(address(this)); require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); destToken.universalTransfer(msg.sender, returnAmount); fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this))); } function swapMulti( IERC20[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory distribution, uint256[] memory flags ) public payable returns(uint256 returnAmount) { tokens[0].universalTransferFrom(msg.sender, address(this), amount); returnAmount = tokens[0].universalBalanceOf(address(this)); for (uint i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } uint256[] memory dist = new uint256[](distribution.length); for (uint j = 0; j < distribution.length; j++) { dist[j] = (distribution[j] >> (8 * (i - 1))) & 0xFF; } _swap( tokens[i - 1], tokens[i], returnAmount, dist, flags[i] ); returnAmount = tokens[i].universalBalanceOf(address(this)); tokens[i - 1].universalTransfer(msg.sender, tokens[i - 1].universalBalanceOf(address(this))); } require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn"); tokens[tokens.length - 1].universalTransfer(msg.sender, returnAmount); } function _swapFloor( IERC20 fromToken, IERC20 destToken, uint256 amount, uint256[] memory distribution, uint256 flags ) internal { fromToken.universalApprove(address(oneSplit), amount); oneSplit.swap.value(fromToken.isETH() ? amount : 0)( fromToken, destToken, amount, 0, distribution, flags ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IOneSplitView","name":"_oneSplitView","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"getExpectedReturn","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"destTokenEthPriceTimesGasPrice","type":"uint256"}],"name":"getExpectedReturnWithGas","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplitView","outputs":[{"internalType":"contract IOneSplitView","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405162004ea838038062004ea88339818101604052602081101561003557600080fd5b5051600080546001600160a01b039092166001600160a01b0319909216919091179055614e4080620000686000396000f3fe60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed9514610289575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102ba565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102dd565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610277600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561020457600080fd5b82018360208201111561021657600080fd5b803590602001918460208302840111600160201b8311171561023757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610434915050565b60408051918252519081900360200190f35b34801561029557600080fd5b5061029e6107f5565b604080516001600160a01b039092168252519081900360200190f35b600060606102cd878787878760006102dd565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035057600080fd5b505afa158015610364573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038d57600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156103b757600080fd5b9083019060208201858111156103cc57600080fd5b82518660208202830111600160201b821117156103e857600080fd5b82525081516020918201928201910280838360005b838110156104155781810151838201526020016103fd565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b031614156104575750836107eb565b61045f614c6c565b604051806103e001604052806108048152602001610a908152602001610add8152602001610e2381526020016110ec8152602001611282815260200161145e815260200161168e81526020016118c88152602001611b028152602001611dab8152602001611fd3815260200161232f8152602001612484815260200161249081526020016124ab81526020016124c681526020016124e1815260200161271b81526020016128a88152602001612a9c8152602001612b488152602001612c1f8152602001612cbe8152602001612eb28152602001612ec08152602001612ece8152602001612edc8152602001612ef98152602001612f0f8152602001612f2f8152509050601f845111156105a45760405162461bcd60e51b8152600401808060200182810382526042815260200180614dca6042913960600191505060405180910390fd5b600080805b86518110156106025760008782815181106105c057fe5b602002602001015111156105fa576105f48782815181106105dd57fe5b602002602001015184612f4590919063ffffffff16565b92508091505b6001016105a9565b50816106625761061a8a6001600160a01b0316612fa8565b156106575760405133903480156108fc02916000818181858888f1935050505015801561064b573d6000803e3d6000fd5b503493505050506107eb565b8793505050506107eb565b61067d6001600160a01b038b1633308b63ffffffff612fe116565b60006106986001600160a01b038c163063ffffffff6130f316565b905060005b875181101561073b578781815181106106b257fe5b6020026020010151600014156106c757610733565b60006106ff856106f38b85815181106106dc57fe5b60200260200101518e61319d90919063ffffffff16565b9063ffffffff6131f616565b90508382141561070c5750815b80830392506107318d8d838b8a87601f811061072457fe5b602002015163ffffffff16565b505b60010161069d565b506107556001600160a01b038b163063ffffffff6130f316565b9450878510156107965760405162461bcd60e51b8152600401808060200182810382526026815260200180614d446026913960400191505060405180910390fd5b6107b06001600160a01b038b16338763ffffffff61323816565b506107e5336107ce6001600160a01b038e163063ffffffff6130f316565b6001600160a01b038e16919063ffffffff61323816565b50505050505b9695505050505050565b6000546001600160a01b031681565b816108176001600160a01b038616612fa8565b61095757604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561087957600080fd5b505afa15801561088d573d6000803e3d6000fd5b505050506040513d60208110156108a357600080fd5b505190506001600160a01b03811615610955576108d06001600160a01b038716828463ffffffff6132b616565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561092657600080fd5b505af115801561093a573d6000803e3d6000fd5b505050506040513d602081101561095057600080fd5b505191505b505b610969846001600160a01b0316612fa8565b610a8957604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109cb57600080fd5b505afa1580156109df573d6000803e3d6000fd5b505050506040513d60208110156109f557600080fd5b505190506001600160a01b03811615610a8757806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a5757600080fd5b505af1158015610a6b573d6000803e3d6000fd5b50505050506040513d6020811015610a8257600080fd5b505191505b505b5050505050565b6040805162461bcd60e51b815260206004820152601a60248201527f5468697320736f75726365207761732064657072656361746564000000000000604482015290519081900360640190fd5b60007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d6020811015610b7157600080fd5b505190506060736f0cd8c4f6f06eab664c7e3031909452b4b728616375e1cc82610ba36001600160a01b038916612fa8565b610bad5787610bc3565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b610bd5886001600160a01b0316612fa8565b610bdf5787610bf5565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060006040518083038186803b158015610c5457600080fd5b505afa158015610c68573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610c9157600080fd5b8101908080516040519392919084600160201b821115610cb057600080fd5b908301906020820185811115610cc557600080fd5b82518660208202830111600160201b82111715610ce157600080fd5b82525081516020918201928201910280838360005b83811015610d0e578181015183820152602001610cf6565b505050509050016040525050509050610d3b8285886001600160a01b03166132b69092919063ffffffff16565b816001600160a01b031663f3898a97610d5c886001600160a01b0316612fa8565b610d67576000610d69565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610dc8578181015183820152602001610db0565b505050509050019450505050506020604051808303818588803b158015610dee57600080fd5b505af1158015610e02573d6000803e3d6000fd5b50505050506040513d6020811015610e1957600080fd5b5050505050505050565b610e35846001600160a01b0316612fa8565b15610e9d57600080516020614c988339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e8357600080fd5b505af1158015610e97573d6000803e3d6000fd5b50505050505b6000610eb1856001600160a01b0316612fa8565b610ebb5784610ecb565b600080516020614c988339815191525b9050610efb6001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff6132b616565b73794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610f276001600160a01b038816612fa8565b610f315786610f41565b600080516020614c988339815191525b85610f54886001600160a01b0316612fa8565b610f5e5787610f6e565b600080516020614c988339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610fcc57600080fd5b505af1158015610fe0573d6000803e3d6000fd5b505050506040513d6020811015610ff657600080fd5b5061100b90506001600160a01b038516612fa8565b15610a8957604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561106357600080fd5b505afa158015611077573d6000803e3d6000fd5b505050506040513d602081101561108d57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156110cd57600080fd5b505af11580156110e1573d6000803e3d6000fd5b505050505050505050565b60006001600160a01b038516600080516020614d2483398151915214611113576000611116565b60025b6001600160a01b038616600080516020614cb88339815191521461113b57600061113e565b60015b0160ff1690506000600080516020614d248339815191526001600160a01b0386161461116b57600061116e565b60025b6001600160a01b038616600080516020614cb883398151915214611193576000611196565b60015b0160ff16905081600f0b600014806111b1575080600f0b6000145b156111bd57505061127c565b6111eb6001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b505af1158015611275573d6000803e3d6000fd5b5050505050505b50505050565b60006001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7146112af5760006112b2565b60035b6001600160a01b038616600080516020614d24833981519152146112d75760006112da565b60025b6001600160a01b038716600080516020614cb8833981519152146112ff576000611302565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b03161461133f576000611342565b60035b6001600160a01b038616600080516020614d248339815191521461136757600061136a565b60025b6001600160a01b038716600080516020614cb88339815191521461138f576000611392565b60015b010160ff16905081600f0b600014806113ae575080600f0b6000145b156113ba57505061127c565b6113e86001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b0385166e085d4780b73119b644ae5ecd22b37614611486576000611489565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146114b45760006114b7565b60035b6001600160a01b038716600080516020614d24833981519152146114dc5760006114df565b60025b6001600160a01b038816600080516020614cb883398151915214611504576000611507565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b031614611540576000611543565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461156e576000611571565b60035b6001600160a01b038716600080516020614d2483398151915214611596576000611599565b60025b6001600160a01b038816600080516020614cb8833981519152146115be5760006115c1565b60015b01010160ff16905081600f0b600014806115de575080600f0b6000145b156115ea57505061127c565b6116186001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c53146116bb5760006116be565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146116e95760006116ec565b60035b6001600160a01b038716600080516020614d2483398151915214611711576000611714565b60025b6001600160a01b038816600080516020614cb88339815191521461173957600061173c565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b03161461177a57600061177d565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146117a85760006117ab565b60035b6001600160a01b038716600080516020614d24833981519152146117d05760006117d3565b60025b6001600160a01b038816600080516020614cb8833981519152146117f85760006117fb565b60015b01010160ff16905081600f0b60001480611818575080600f0b6000145b1561182457505061127c565b6118526001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f51146118f55760006118f8565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611923576000611926565b60035b6001600160a01b038716600080516020614d248339815191521461194b57600061194e565b60025b6001600160a01b038816600080516020614cb883398151915214611973576000611976565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b0316146119b45760006119b7565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146119e25760006119e5565b60035b6001600160a01b038716600080516020614d2483398151915214611a0a576000611a0d565b60025b6001600160a01b038816600080516020614cb883398151915214611a32576000611a35565b60015b01010160ff16905081600f0b60001480611a52575080600f0b6000145b15611a5e57505061127c565b611a8c6001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b611b14846001600160a01b0316612fa8565b611c5b57604080516332a5d5bf60e01b81526001600160a01b0386166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611b7657600080fd5b505afa158015611b8a573d6000803e3d6000fd5b505050506040513d6020811015611ba057600080fd5b50519050611bbe6001600160a01b038616828563ffffffff6132b616565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c0457600080fd5b505af1158015611c18573d6000803e3d6000fd5b505050506040513d6020811015611c2e57600080fd5b50611c5590508185611c4f6001600160a01b0383163063ffffffff6130f316565b85610804565b5061127c565b611c6d836001600160a01b0316612fa8565b61127c57604080516332a5d5bf60e01b81526001600160a01b0385166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d6020811015611cf957600080fd5b50519050611d0985828585610804565b6001600160a01b03811663db006a75611d28823063ffffffff6130f316565b6040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b505050506040513d6020811015611d8857600080fd5b50611da490506001600160a01b0385163063ffffffff6130f316565b505061127c565b6001600160a01b038416600080516020614cb88339815191521415611ea057611df86001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff6132b616565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611e5157600080fd5b505af1158015611e65573d6000803e3d6000fd5b50611e9b92507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611e95823063ffffffff6130f316565b84610804565b61127c565b6001600160a01b038316600080516020614cb8833981519152141561127c57611edf847306af07097c9eeb7fd685c692751d5c66db49c2158484610804565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c2159263ef693bed92909184916370a08231916024808301926020929190829003018186803b158015611f3c57600080fd5b505afa158015611f50573d6000803e3d6000fd5b505050506040513d6020811015611f6657600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015611fb657600080fd5b505af1158015611fca573d6000803e3d6000fd5b5050505061127c565b611fe5846001600160a01b0316612fa8565b6121ab5760408051635f5418f360e01b81526001600160a01b0386166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561204757600080fd5b505afa15801561205b573d6000803e3d6000fd5b505050506040513d602081101561207157600080fd5b50516040805163797a759360e11b815290519192506121089173398ec7346dcd622edc5ae82352f02be94c62d1199163f2f4eb26916004808301926020929190829003018186803b1580156120c557600080fd5b505afa1580156120d9573d6000803e3d6000fd5b505050506040513d60208110156120ef57600080fd5b50516001600160a01b038716908563ffffffff6132b616565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b15801561217257600080fd5b505af1158015612186573d6000803e3d6000fd5b50505050611c558185611c4f30856001600160a01b03166130f390919063ffffffff16565b6121bd836001600160a01b0316612fa8565b61127c5760408051635f5418f360e01b81526001600160a01b0385166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561221f57600080fd5b505afa158015612233573d6000803e3d6000fd5b505050506040513d602081101561224957600080fd5b5051905061225985828585610804565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163db006a759183916370a08231916024808301926020929190829003018186803b1580156122a757600080fd5b505afa1580156122bb573d6000803e3d6000fd5b505050506040513d60208110156122d157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561231157600080fd5b505af1158015612325573d6000803e3d6000fd5b505050505061127c565b6000737079e8517594e5b21d2b9a0d17cb33f5fe2bca706001600160a01b031663d4b839926040518163ffffffff1660e01b815260040160206040518083038186803b15801561237e57600080fd5b505afa158015612392573d6000803e3d6000fd5b505050506040513d60208110156123a857600080fd5b505190506123c66001600160a01b038616828563ffffffff6132b616565b806001600160a01b031663fe0291566123e7876001600160a01b0316612fa8565b6123f25760006123f4565b845b604080516001600160e01b031960e085901b1681526001600160a01b03808b1660048301528916602482015260448101889052600060648201529051608480830192602092919082900301818588803b15801561245057600080fd5b505af1158015612464573d6000803e3d6000fd5b50505050506040513d602081101561247b57600080fd5b50505050505050565b610a89848484846133af565b61127c84600080516020614c98833981519152858585613761565b61127c84600080516020614cb8833981519152858585613761565b61127c84600080516020614d24833981519152858585613761565b60006001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e11461250e576000612511565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461253c57600061253f565b60035b6001600160a01b038716600080516020614d2483398151915214612564576000612567565b60025b6001600160a01b038816600080516020614cb88339815191521461258c57600061258f565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146125cd5760006125d0565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146125fb5760006125fe565b60035b6001600160a01b038716600080516020614d2483398151915214612623576000612626565b60025b6001600160a01b038816600080516020614cb88339815191521461264b57600061264e565b60015b01010160ff16905081600f0b6000148061266b575080600f0b6000145b1561267757505061127c565b6126a56001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c5991461274857600061274b565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612776576000612779565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b038616146127ac5760006127af565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146127da5760006127dd565b60015b0160ff16905081600f0b600014806127f8575080600f0b6000145b1561280457505061127c565b6128326001600160a01b0387167393054188d876f558f4a66b2ef1d97d16edf0895b8663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517393054188d876f558f4a66b2ef1d97d16edf0895b92633df02124926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146128d55760006128d8565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612903576000612906565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612931576000612934565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612971576000612974565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c5991461299f5760006129a2565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd847146129cd5760006129d0565b60015b010160ff16905081600f0b600014806129ec575080600f0b6000145b156129f857505061127c565b612a266001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561126157600080fd5b612aca6001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff6132b616565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b158015612b3457600080fd5b505af1158015610e19573d6000803e3d6000fd5b612b766001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff6132b616565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b158015612bf557600080fd5b505af1158015612c09573d6000803e3d6000fd5b505050506040513d6020811015610a8757600080fd5b612c4d6001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff6132b616565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015612bf557600080fd5b60006001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612ceb576000612cee565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612d19576000612d1c565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612d47576000612d4a565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612d87576000612d8a565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612db5576000612db8565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612de3576000612de6565b60015b010160ff16905081600f0b60001480612e02575080600f0b6000145b15612e0e57505061127c565b612e3c6001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561126157600080fd5b61127c848484846000613778565b61127c848484846001613778565b61127c848484846002613778565b61127c848484846001685a434ecd46efdcc7c760b11b0319613be9565b61127c84848484600161543360e81b0319613be9565b61127c8484848460016b2c2466af65a2f7eba2a7a463609a1b0319613be9565b61127c84848484612f408989614443565b613be9565b600082820183811015612f9f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b0382161580612fa257506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b80612feb5761127c565b612ff484612fa8565b156130d8576001600160a01b038316331480156130115750803410155b61304c5760405162461bcd60e51b815260040180806020018281038252602b815260200180614cd8602b913960400191505060405180910390fd5b6001600160a01b0382163014613094576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613092573d6000803e3d6000fd5b505b80341115611e9b57336108fc6130b0348463ffffffff6146be16565b6040518115909202916000818181858888f19350505050158015611c55573d6000803e3d6000fd5b61127c6001600160a01b03851684848463ffffffff61470016565b60006130fe83612fa8565b1561311457506001600160a01b03811631612fa2565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d602081101561319457600080fd5b50519050612fa2565b6000826131ac57506000612fa2565b828202828482816131b957fe5b0414612f9f5760405162461bcd60e51b8152600401808060200182810382526021815260200180614d036021913960400191505060405180910390fd5b6000612f9f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061475a565b600081613247575060016132af565b61325084612fa8565b15613291576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561328b573d6000803e3d6000fd5b506132af565b6132ab6001600160a01b038516848463ffffffff6147fc16565b5060015b9392505050565b6132bf83612fa8565b6133aa57806132e8576132e36001600160a01b03841683600063ffffffff61484e16565b6133aa565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561333957600080fd5b505afa15801561334d573d6000803e3d6000fd5b505050506040513d602081101561336357600080fd5b505190508181101561127c578015613390576133906001600160a01b03851684600063ffffffff61484e16565b61127c6001600160a01b038516848463ffffffff61484e16565b505050565b60006133c3856001600160a01b0316612fa8565b1561342b57600080516020614c988339815191526001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561341157600080fd5b505af1158015613425573d6000803e3d6000fd5b50505050505b600061343f866001600160a01b0316612fa8565b6134495785613459565b600080516020614c988339815191525b9050600061346f866001600160a01b0316612fa8565b6134795785613489565b600080516020614c988339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d602081101561351b57600080fd5b5051905061353a6001600160a01b03821684848963ffffffff61496116565b93506135566001600160a01b038416828863ffffffff61323816565b50816001600160a01b0316836001600160a01b031610156135ef576040805163022c0d9f60e01b815260006004820181905260248201879052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b50505050613669565b6040805163022c0d9f60e01b815260048101869052600060248201819052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b15801561365057600080fd5b505af1158015613664573d6000803e3d6000fd5b505050505b61367b876001600160a01b0316612fa8565b1561375657604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156136d357600080fd5b505afa1580156136e7573d6000803e3d6000fd5b505050506040513d60208110156136fd57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561373d57600080fd5b505af1158015613751573d6000803e3d6000fd5b505050505b505050949350505050565b610a878484613772888887876133af565b846133af565b60607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc436137a66001600160a01b038916612fa8565b6137b057876137c0565b600080516020614c988339815191525b6137d2886001600160a01b0316612fa8565b6137dc57876137ec565b600080516020614c988339815191525b856001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b15801561385657600080fd5b505afa15801561386a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561389357600080fd5b8101908080516040519392919084600160201b8211156138b257600080fd5b9083019060208201858111156138c757600080fd5b82518660208202830111600160201b821117156138e357600080fd5b82525081516020918201928201910280838360005b838110156139105781810151838201526020016138f8565b505050509050016040525050509050613931866001600160a01b0316612fa8565b1561399957600080516020614c988339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397f57600080fd5b505af1158015613993573d6000803e3d6000fd5b50505050505b6139f38183815181106139a857fe5b6020026020010151856139c3896001600160a01b0316612fa8565b6139cd57886139dd565b600080516020614c988339815191525b6001600160a01b0316919063ffffffff6132b616565b8082815181106139ff57fe5b60200260200101516001600160a01b0316638201aa3f613a27886001600160a01b0316612fa8565b613a315787613a41565b600080516020614c988339815191525b86613a54896001600160a01b0316612fa8565b613a5e5788613a6e565b600080516020614c988339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b158015613ae857600080fd5b505af1158015613afc573d6000803e3d6000fd5b505050506040513d6040811015613b1257600080fd5b50613b2790506001600160a01b038616612fa8565b15610a8757604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613b7f57600080fd5b505afa158015613b93573d6000803e3d6000fd5b505050506040513d6020811015613ba957600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561126157600080fd5b826000613c0084600160ff1b63ffffffff614a1816565b613c0b576000613c0e565b600a5b60408051600180825281830190925260ff92909216925060609190602080830190803883390190505090508381600081518110613c4757fe5b602002602001018181525050613c65886001600160a01b0316612fa8565b61405f57606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166361e597f98a6001856000604051908082528060200260200182016040528015613cbd578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001846003811115613cf557fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015613d3d578181015183820152602001613d25565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015613d7c578181015183820152602001613d64565b50505050905001965050505050505060006040518083038186803b158015613da357600080fd5b505afa158015613db7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015613de057600080fd5b8101908080516040519392919084600160201b821115613dff57600080fd5b908301906020820185811115613e1457600080fd5b8251600160201b811182820188101715613e2d57600080fd5b82525081516020918201929091019080838360005b83811015613e5a578181015183820152602001613e42565b50505050905090810190601f168015613e875780820380516001836020036101000a031916815260200191505b5060405250919250613ec09150506001600160a01b038a16739aab3f75489902f3a48495025729a0af77d4b11e8963ffffffff6132b616565b739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548a8673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee306000196000734d37f28d2db99e8d35a6c725a5f1749a085850a38b8a6040518a63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613fdb578181015183820152602001613fc3565b50505050905090810190601f1680156140085780820380516001836020036101000a031916815260200191505b509a5050505050505050505050602060405180830381600087803b15801561402f57600080fd5b505af1158015614043573d6000803e3d6000fd5b505050506040513d602081101561405957600080fd5b50519350505b614071876001600160a01b0316612fa8565b610e1957606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166381efcbdd8960018560006040519080825280602002602001820160405280156140c9578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b0316815260200184600381111561410157fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015614149578181015183820152602001614131565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015614188578181015183820152602001614170565b50505050905001965050505050505060006040518083038186803b1580156141af57600080fd5b505afa1580156141c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156141ec57600080fd5b8101908080516040519392919084600160201b82111561420b57600080fd5b90830190602082018581111561422057600080fd5b8251600160201b81118282018810171561423957600080fd5b82525081516020918201929091019080838360005b8381101561426657818101518382015260200161424e565b50505050905090810190601f1680156142935780820380516001836020036101000a031916815260200191505b506040525050509050739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee878c306000196000734d37f28d2db99e8d35a6c725a5f1749a085850a38c8b6040518b63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156143b85781810151838201526020016143a0565b50505050905090810190601f1680156143e55780820380516001836020036101000a031916815260200191505b509a50505050505050505050506020604051808303818588803b15801561440b57600080fd5b505af115801561441f573d6000803e3d6000fd5b50505050506040513d602081101561443657600080fd5b5050505050505050505050565b6000614457836001600160a01b0316612fa8565b1580156144735750614471826001600160a01b0316612fa8565b155b1561448057506000612fa2565b606073c8fb12402cb16970f3c5f4b48ff68eb9d1289301633d3dc52c6144ae6001600160a01b038716612fa8565b6144b857856144ba565b845b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060006040518083038186803b15801561450057600080fd5b505afa158015614514573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561453d57600080fd5b8101908080516040519392919084600160201b82111561455c57600080fd5b90830190602082018581111561457157600080fd5b82518660208202830111600160201b8211171561458d57600080fd5b82525081516020918201928201910280838360005b838110156145ba5781810151838201526020016145a2565b50505050905001604052505050905060008090505b81518110156146b35760f88282815181106145e657fe5b602002602001015160001c901c60bb14158015614629575081818151811061460a57fe5b60200260200101516001685a434ecd46efdcc7c760b11b031960001b14155b8015614654575081818151811061463c57fe5b6020026020010151600161543360e81b031960001b14155b8015614689575081818151811061466757fe5b602002602001015160016b2c2466af65a2f7eba2a7a463609a1b031960001b14155b156146ab5781818151811061469a57fe5b602002602001015192505050612fa2565b6001016145cf565b506000949350505050565b6000612f9f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614a1e565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261127c908590614a78565b600081836147e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156147ab578181015183820152602001614793565b50505050905090810190601f1680156147d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816147f257fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526133aa908490614a78565b8015806148d4575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156148a657600080fd5b505afa1580156148ba573d6000803e3d6000fd5b505050506040513d60208110156148d057600080fd5b5051155b61490f5760405162461bcd60e51b8152600401808060200182810382526036815260200180614d946036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526133aa908490614a78565b60008061497d6001600160a01b0386168763ffffffff6130f316565b9050600061499a6001600160a01b0386168863ffffffff6130f316565b905060006149b0856103e563ffffffff61319d16565b905060006149c4828463ffffffff61319d16565b905060006149ea836149de876103e863ffffffff61319d16565b9063ffffffff612f4516565b90508015614a0757614a02828263ffffffff6131f616565b614a0a565b60005b9a9950505050505050505050565b16151590565b60008184841115614a705760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156147ab578181015183820152602001614793565b505050900390565b614a8a826001600160a01b0316614c30565b614adb576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614b195780518252601f199092019160209182019101614afa565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614b7b576040519150601f19603f3d011682016040523d82523d6000602084013e614b80565b606091505b509150915081614bd7576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561127c57808060200190516020811015614bf357600080fd5b505161127c5760405162461bcd60e51b815260040180806020018281038252602a815260200180614d6a602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614c6457508115155b949350505050565b604051806103e00160405280601f905b614c95815260200190600190039081614c7c5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a723158203ce6424499244d5df6d946ff1e1427463472a95150dd93d28a25f4ce749fd82864736f6c634300051100320000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f5
Deployed Bytecode
0x60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed9514610289575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102ba565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102dd565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610277600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561020457600080fd5b82018360208201111561021657600080fd5b803590602001918460208302840111600160201b8311171561023757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610434915050565b60408051918252519081900360200190f35b34801561029557600080fd5b5061029e6107f5565b604080516001600160a01b039092168252519081900360200190f35b600060606102cd878787878760006102dd565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035057600080fd5b505afa158015610364573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038d57600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156103b757600080fd5b9083019060208201858111156103cc57600080fd5b82518660208202830111600160201b821117156103e857600080fd5b82525081516020918201928201910280838360005b838110156104155781810151838201526020016103fd565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b031614156104575750836107eb565b61045f614c6c565b604051806103e001604052806108048152602001610a908152602001610add8152602001610e2381526020016110ec8152602001611282815260200161145e815260200161168e81526020016118c88152602001611b028152602001611dab8152602001611fd3815260200161232f8152602001612484815260200161249081526020016124ab81526020016124c681526020016124e1815260200161271b81526020016128a88152602001612a9c8152602001612b488152602001612c1f8152602001612cbe8152602001612eb28152602001612ec08152602001612ece8152602001612edc8152602001612ef98152602001612f0f8152602001612f2f8152509050601f845111156105a45760405162461bcd60e51b8152600401808060200182810382526042815260200180614dca6042913960600191505060405180910390fd5b600080805b86518110156106025760008782815181106105c057fe5b602002602001015111156105fa576105f48782815181106105dd57fe5b602002602001015184612f4590919063ffffffff16565b92508091505b6001016105a9565b50816106625761061a8a6001600160a01b0316612fa8565b156106575760405133903480156108fc02916000818181858888f1935050505015801561064b573d6000803e3d6000fd5b503493505050506107eb565b8793505050506107eb565b61067d6001600160a01b038b1633308b63ffffffff612fe116565b60006106986001600160a01b038c163063ffffffff6130f316565b905060005b875181101561073b578781815181106106b257fe5b6020026020010151600014156106c757610733565b60006106ff856106f38b85815181106106dc57fe5b60200260200101518e61319d90919063ffffffff16565b9063ffffffff6131f616565b90508382141561070c5750815b80830392506107318d8d838b8a87601f811061072457fe5b602002015163ffffffff16565b505b60010161069d565b506107556001600160a01b038b163063ffffffff6130f316565b9450878510156107965760405162461bcd60e51b8152600401808060200182810382526026815260200180614d446026913960400191505060405180910390fd5b6107b06001600160a01b038b16338763ffffffff61323816565b506107e5336107ce6001600160a01b038e163063ffffffff6130f316565b6001600160a01b038e16919063ffffffff61323816565b50505050505b9695505050505050565b6000546001600160a01b031681565b816108176001600160a01b038616612fa8565b61095757604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561087957600080fd5b505afa15801561088d573d6000803e3d6000fd5b505050506040513d60208110156108a357600080fd5b505190506001600160a01b03811615610955576108d06001600160a01b038716828463ffffffff6132b616565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561092657600080fd5b505af115801561093a573d6000803e3d6000fd5b505050506040513d602081101561095057600080fd5b505191505b505b610969846001600160a01b0316612fa8565b610a8957604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109cb57600080fd5b505afa1580156109df573d6000803e3d6000fd5b505050506040513d60208110156109f557600080fd5b505190506001600160a01b03811615610a8757806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a5757600080fd5b505af1158015610a6b573d6000803e3d6000fd5b50505050506040513d6020811015610a8257600080fd5b505191505b505b5050505050565b6040805162461bcd60e51b815260206004820152601a60248201527f5468697320736f75726365207761732064657072656361746564000000000000604482015290519081900360640190fd5b60007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d6020811015610b7157600080fd5b505190506060736f0cd8c4f6f06eab664c7e3031909452b4b728616375e1cc82610ba36001600160a01b038916612fa8565b610bad5787610bc3565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b610bd5886001600160a01b0316612fa8565b610bdf5787610bf5565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060006040518083038186803b158015610c5457600080fd5b505afa158015610c68573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610c9157600080fd5b8101908080516040519392919084600160201b821115610cb057600080fd5b908301906020820185811115610cc557600080fd5b82518660208202830111600160201b82111715610ce157600080fd5b82525081516020918201928201910280838360005b83811015610d0e578181015183820152602001610cf6565b505050509050016040525050509050610d3b8285886001600160a01b03166132b69092919063ffffffff16565b816001600160a01b031663f3898a97610d5c886001600160a01b0316612fa8565b610d67576000610d69565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610dc8578181015183820152602001610db0565b505050509050019450505050506020604051808303818588803b158015610dee57600080fd5b505af1158015610e02573d6000803e3d6000fd5b50505050506040513d6020811015610e1957600080fd5b5050505050505050565b610e35846001600160a01b0316612fa8565b15610e9d57600080516020614c988339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e8357600080fd5b505af1158015610e97573d6000803e3d6000fd5b50505050505b6000610eb1856001600160a01b0316612fa8565b610ebb5784610ecb565b600080516020614c988339815191525b9050610efb6001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff6132b616565b73794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610f276001600160a01b038816612fa8565b610f315786610f41565b600080516020614c988339815191525b85610f54886001600160a01b0316612fa8565b610f5e5787610f6e565b600080516020614c988339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610fcc57600080fd5b505af1158015610fe0573d6000803e3d6000fd5b505050506040513d6020811015610ff657600080fd5b5061100b90506001600160a01b038516612fa8565b15610a8957604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561106357600080fd5b505afa158015611077573d6000803e3d6000fd5b505050506040513d602081101561108d57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156110cd57600080fd5b505af11580156110e1573d6000803e3d6000fd5b505050505050505050565b60006001600160a01b038516600080516020614d2483398151915214611113576000611116565b60025b6001600160a01b038616600080516020614cb88339815191521461113b57600061113e565b60015b0160ff1690506000600080516020614d248339815191526001600160a01b0386161461116b57600061116e565b60025b6001600160a01b038616600080516020614cb883398151915214611193576000611196565b60015b0160ff16905081600f0b600014806111b1575080600f0b6000145b156111bd57505061127c565b6111eb6001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b505af1158015611275573d6000803e3d6000fd5b5050505050505b50505050565b60006001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7146112af5760006112b2565b60035b6001600160a01b038616600080516020614d24833981519152146112d75760006112da565b60025b6001600160a01b038716600080516020614cb8833981519152146112ff576000611302565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b03161461133f576000611342565b60035b6001600160a01b038616600080516020614d248339815191521461136757600061136a565b60025b6001600160a01b038716600080516020614cb88339815191521461138f576000611392565b60015b010160ff16905081600f0b600014806113ae575080600f0b6000145b156113ba57505061127c565b6113e86001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b0385166e085d4780b73119b644ae5ecd22b37614611486576000611489565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146114b45760006114b7565b60035b6001600160a01b038716600080516020614d24833981519152146114dc5760006114df565b60025b6001600160a01b038816600080516020614cb883398151915214611504576000611507565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b031614611540576000611543565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461156e576000611571565b60035b6001600160a01b038716600080516020614d2483398151915214611596576000611599565b60025b6001600160a01b038816600080516020614cb8833981519152146115be5760006115c1565b60015b01010160ff16905081600f0b600014806115de575080600f0b6000145b156115ea57505061127c565b6116186001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c53146116bb5760006116be565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146116e95760006116ec565b60035b6001600160a01b038716600080516020614d2483398151915214611711576000611714565b60025b6001600160a01b038816600080516020614cb88339815191521461173957600061173c565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b03161461177a57600061177d565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146117a85760006117ab565b60035b6001600160a01b038716600080516020614d24833981519152146117d05760006117d3565b60025b6001600160a01b038816600080516020614cb8833981519152146117f85760006117fb565b60015b01010160ff16905081600f0b60001480611818575080600f0b6000145b1561182457505061127c565b6118526001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f51146118f55760006118f8565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611923576000611926565b60035b6001600160a01b038716600080516020614d248339815191521461194b57600061194e565b60025b6001600160a01b038816600080516020614cb883398151915214611973576000611976565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b0316146119b45760006119b7565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146119e25760006119e5565b60035b6001600160a01b038716600080516020614d2483398151915214611a0a576000611a0d565b60025b6001600160a01b038816600080516020614cb883398151915214611a32576000611a35565b60015b01010160ff16905081600f0b60001480611a52575080600f0b6000145b15611a5e57505061127c565b611a8c6001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b611b14846001600160a01b0316612fa8565b611c5b57604080516332a5d5bf60e01b81526001600160a01b0386166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611b7657600080fd5b505afa158015611b8a573d6000803e3d6000fd5b505050506040513d6020811015611ba057600080fd5b50519050611bbe6001600160a01b038616828563ffffffff6132b616565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c0457600080fd5b505af1158015611c18573d6000803e3d6000fd5b505050506040513d6020811015611c2e57600080fd5b50611c5590508185611c4f6001600160a01b0383163063ffffffff6130f316565b85610804565b5061127c565b611c6d836001600160a01b0316612fa8565b61127c57604080516332a5d5bf60e01b81526001600160a01b0385166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d6020811015611cf957600080fd5b50519050611d0985828585610804565b6001600160a01b03811663db006a75611d28823063ffffffff6130f316565b6040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b505050506040513d6020811015611d8857600080fd5b50611da490506001600160a01b0385163063ffffffff6130f316565b505061127c565b6001600160a01b038416600080516020614cb88339815191521415611ea057611df86001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff6132b616565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611e5157600080fd5b505af1158015611e65573d6000803e3d6000fd5b50611e9b92507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611e95823063ffffffff6130f316565b84610804565b61127c565b6001600160a01b038316600080516020614cb8833981519152141561127c57611edf847306af07097c9eeb7fd685c692751d5c66db49c2158484610804565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c2159263ef693bed92909184916370a08231916024808301926020929190829003018186803b158015611f3c57600080fd5b505afa158015611f50573d6000803e3d6000fd5b505050506040513d6020811015611f6657600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015611fb657600080fd5b505af1158015611fca573d6000803e3d6000fd5b5050505061127c565b611fe5846001600160a01b0316612fa8565b6121ab5760408051635f5418f360e01b81526001600160a01b0386166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561204757600080fd5b505afa15801561205b573d6000803e3d6000fd5b505050506040513d602081101561207157600080fd5b50516040805163797a759360e11b815290519192506121089173398ec7346dcd622edc5ae82352f02be94c62d1199163f2f4eb26916004808301926020929190829003018186803b1580156120c557600080fd5b505afa1580156120d9573d6000803e3d6000fd5b505050506040513d60208110156120ef57600080fd5b50516001600160a01b038716908563ffffffff6132b616565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b15801561217257600080fd5b505af1158015612186573d6000803e3d6000fd5b50505050611c558185611c4f30856001600160a01b03166130f390919063ffffffff16565b6121bd836001600160a01b0316612fa8565b61127c5760408051635f5418f360e01b81526001600160a01b0385166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561221f57600080fd5b505afa158015612233573d6000803e3d6000fd5b505050506040513d602081101561224957600080fd5b5051905061225985828585610804565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163db006a759183916370a08231916024808301926020929190829003018186803b1580156122a757600080fd5b505afa1580156122bb573d6000803e3d6000fd5b505050506040513d60208110156122d157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561231157600080fd5b505af1158015612325573d6000803e3d6000fd5b505050505061127c565b6000737079e8517594e5b21d2b9a0d17cb33f5fe2bca706001600160a01b031663d4b839926040518163ffffffff1660e01b815260040160206040518083038186803b15801561237e57600080fd5b505afa158015612392573d6000803e3d6000fd5b505050506040513d60208110156123a857600080fd5b505190506123c66001600160a01b038616828563ffffffff6132b616565b806001600160a01b031663fe0291566123e7876001600160a01b0316612fa8565b6123f25760006123f4565b845b604080516001600160e01b031960e085901b1681526001600160a01b03808b1660048301528916602482015260448101889052600060648201529051608480830192602092919082900301818588803b15801561245057600080fd5b505af1158015612464573d6000803e3d6000fd5b50505050506040513d602081101561247b57600080fd5b50505050505050565b610a89848484846133af565b61127c84600080516020614c98833981519152858585613761565b61127c84600080516020614cb8833981519152858585613761565b61127c84600080516020614d24833981519152858585613761565b60006001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e11461250e576000612511565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461253c57600061253f565b60035b6001600160a01b038716600080516020614d2483398151915214612564576000612567565b60025b6001600160a01b038816600080516020614cb88339815191521461258c57600061258f565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146125cd5760006125d0565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146125fb5760006125fe565b60035b6001600160a01b038716600080516020614d2483398151915214612623576000612626565b60025b6001600160a01b038816600080516020614cb88339815191521461264b57600061264e565b60015b01010160ff16905081600f0b6000148061266b575080600f0b6000145b1561267757505061127c565b6126a56001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff6132b616565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c5991461274857600061274b565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612776576000612779565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b038616146127ac5760006127af565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146127da5760006127dd565b60015b0160ff16905081600f0b600014806127f8575080600f0b6000145b1561280457505061127c565b6128326001600160a01b0387167393054188d876f558f4a66b2ef1d97d16edf0895b8663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517393054188d876f558f4a66b2ef1d97d16edf0895b92633df02124926084808201939182900301818387803b15801561126157600080fd5b60006001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146128d55760006128d8565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612903576000612906565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612931576000612934565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612971576000612974565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c5991461299f5760006129a2565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd847146129cd5760006129d0565b60015b010160ff16905081600f0b600014806129ec575080600f0b6000145b156129f857505061127c565b612a266001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561126157600080fd5b612aca6001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff6132b616565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b158015612b3457600080fd5b505af1158015610e19573d6000803e3d6000fd5b612b766001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff6132b616565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b158015612bf557600080fd5b505af1158015612c09573d6000803e3d6000fd5b505050506040513d6020811015610a8757600080fd5b612c4d6001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff6132b616565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015612bf557600080fd5b60006001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612ceb576000612cee565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612d19576000612d1c565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612d47576000612d4a565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612d87576000612d8a565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612db5576000612db8565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612de3576000612de6565b60015b010160ff16905081600f0b60001480612e02575080600f0b6000145b15612e0e57505061127c565b612e3c6001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff6132b616565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561126157600080fd5b61127c848484846000613778565b61127c848484846001613778565b61127c848484846002613778565b61127c848484846001685a434ecd46efdcc7c760b11b0319613be9565b61127c84848484600161543360e81b0319613be9565b61127c8484848460016b2c2466af65a2f7eba2a7a463609a1b0319613be9565b61127c84848484612f408989614443565b613be9565b600082820183811015612f9f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b0382161580612fa257506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b80612feb5761127c565b612ff484612fa8565b156130d8576001600160a01b038316331480156130115750803410155b61304c5760405162461bcd60e51b815260040180806020018281038252602b815260200180614cd8602b913960400191505060405180910390fd5b6001600160a01b0382163014613094576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613092573d6000803e3d6000fd5b505b80341115611e9b57336108fc6130b0348463ffffffff6146be16565b6040518115909202916000818181858888f19350505050158015611c55573d6000803e3d6000fd5b61127c6001600160a01b03851684848463ffffffff61470016565b60006130fe83612fa8565b1561311457506001600160a01b03811631612fa2565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561316a57600080fd5b505afa15801561317e573d6000803e3d6000fd5b505050506040513d602081101561319457600080fd5b50519050612fa2565b6000826131ac57506000612fa2565b828202828482816131b957fe5b0414612f9f5760405162461bcd60e51b8152600401808060200182810382526021815260200180614d036021913960400191505060405180910390fd5b6000612f9f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061475a565b600081613247575060016132af565b61325084612fa8565b15613291576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561328b573d6000803e3d6000fd5b506132af565b6132ab6001600160a01b038516848463ffffffff6147fc16565b5060015b9392505050565b6132bf83612fa8565b6133aa57806132e8576132e36001600160a01b03841683600063ffffffff61484e16565b6133aa565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561333957600080fd5b505afa15801561334d573d6000803e3d6000fd5b505050506040513d602081101561336357600080fd5b505190508181101561127c578015613390576133906001600160a01b03851684600063ffffffff61484e16565b61127c6001600160a01b038516848463ffffffff61484e16565b505050565b60006133c3856001600160a01b0316612fa8565b1561342b57600080516020614c988339815191526001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561341157600080fd5b505af1158015613425573d6000803e3d6000fd5b50505050505b600061343f866001600160a01b0316612fa8565b6134495785613459565b600080516020614c988339815191525b9050600061346f866001600160a01b0316612fa8565b6134795785613489565b600080516020614c988339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d602081101561351b57600080fd5b5051905061353a6001600160a01b03821684848963ffffffff61496116565b93506135566001600160a01b038416828863ffffffff61323816565b50816001600160a01b0316836001600160a01b031610156135ef576040805163022c0d9f60e01b815260006004820181905260248201879052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b1580156135d257600080fd5b505af11580156135e6573d6000803e3d6000fd5b50505050613669565b6040805163022c0d9f60e01b815260048101869052600060248201819052306044830152608060648301526084820181905291516001600160a01b0384169263022c0d9f9260c4808201939182900301818387803b15801561365057600080fd5b505af1158015613664573d6000803e3d6000fd5b505050505b61367b876001600160a01b0316612fa8565b1561375657604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156136d357600080fd5b505afa1580156136e7573d6000803e3d6000fd5b505050506040513d60208110156136fd57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561373d57600080fd5b505af1158015613751573d6000803e3d6000fd5b505050505b505050949350505050565b610a878484613772888887876133af565b846133af565b60607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc436137a66001600160a01b038916612fa8565b6137b057876137c0565b600080516020614c988339815191525b6137d2886001600160a01b0316612fa8565b6137dc57876137ec565b600080516020614c988339815191525b856001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b15801561385657600080fd5b505afa15801561386a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561389357600080fd5b8101908080516040519392919084600160201b8211156138b257600080fd5b9083019060208201858111156138c757600080fd5b82518660208202830111600160201b821117156138e357600080fd5b82525081516020918201928201910280838360005b838110156139105781810151838201526020016138f8565b505050509050016040525050509050613931866001600160a01b0316612fa8565b1561399957600080516020614c988339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561397f57600080fd5b505af1158015613993573d6000803e3d6000fd5b50505050505b6139f38183815181106139a857fe5b6020026020010151856139c3896001600160a01b0316612fa8565b6139cd57886139dd565b600080516020614c988339815191525b6001600160a01b0316919063ffffffff6132b616565b8082815181106139ff57fe5b60200260200101516001600160a01b0316638201aa3f613a27886001600160a01b0316612fa8565b613a315787613a41565b600080516020614c988339815191525b86613a54896001600160a01b0316612fa8565b613a5e5788613a6e565b600080516020614c988339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b158015613ae857600080fd5b505af1158015613afc573d6000803e3d6000fd5b505050506040513d6040811015613b1257600080fd5b50613b2790506001600160a01b038616612fa8565b15610a8757604080516370a0823160e01b81523060048201529051600080516020614c9883398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613b7f57600080fd5b505afa158015613b93573d6000803e3d6000fd5b505050506040513d6020811015613ba957600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561126157600080fd5b826000613c0084600160ff1b63ffffffff614a1816565b613c0b576000613c0e565b600a5b60408051600180825281830190925260ff92909216925060609190602080830190803883390190505090508381600081518110613c4757fe5b602002602001018181525050613c65886001600160a01b0316612fa8565b61405f57606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166361e597f98a6001856000604051908082528060200260200182016040528015613cbd578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001846003811115613cf557fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015613d3d578181015183820152602001613d25565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015613d7c578181015183820152602001613d64565b50505050905001965050505050505060006040518083038186803b158015613da357600080fd5b505afa158015613db7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015613de057600080fd5b8101908080516040519392919084600160201b821115613dff57600080fd5b908301906020820185811115613e1457600080fd5b8251600160201b811182820188101715613e2d57600080fd5b82525081516020918201929091019080838360005b83811015613e5a578181015183820152602001613e42565b50505050905090810190601f168015613e875780820380516001836020036101000a031916815260200191505b5060405250919250613ec09150506001600160a01b038a16739aab3f75489902f3a48495025729a0af77d4b11e8963ffffffff6132b616565b739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548a8673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee306000196000734d37f28d2db99e8d35a6c725a5f1749a085850a38b8a6040518a63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015613fdb578181015183820152602001613fc3565b50505050905090810190601f1680156140085780820380516001836020036101000a031916815260200191505b509a5050505050505050505050602060405180830381600087803b15801561402f57600080fd5b505af1158015614043573d6000803e3d6000fd5b505050506040513d602081101561405957600080fd5b50519350505b614071876001600160a01b0316612fa8565b610e1957606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166381efcbdd8960018560006040519080825280602002602001820160405280156140c9578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b0316815260200184600381111561410157fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015614149578181015183820152602001614131565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015614188578181015183820152602001614170565b50505050905001965050505050505060006040518083038186803b1580156141af57600080fd5b505afa1580156141c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156141ec57600080fd5b8101908080516040519392919084600160201b82111561420b57600080fd5b90830190602082018581111561422057600080fd5b8251600160201b81118282018810171561423957600080fd5b82525081516020918201929091019080838360005b8381101561426657818101518382015260200161424e565b50505050905090810190601f1680156142935780820380516001836020036101000a031916815260200191505b506040525050509050739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee878c306000196000734d37f28d2db99e8d35a6c725a5f1749a085850a38c8b6040518b63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156143b85781810151838201526020016143a0565b50505050905090810190601f1680156143e55780820380516001836020036101000a031916815260200191505b509a50505050505050505050506020604051808303818588803b15801561440b57600080fd5b505af115801561441f573d6000803e3d6000fd5b50505050506040513d602081101561443657600080fd5b5050505050505050505050565b6000614457836001600160a01b0316612fa8565b1580156144735750614471826001600160a01b0316612fa8565b155b1561448057506000612fa2565b606073c8fb12402cb16970f3c5f4b48ff68eb9d1289301633d3dc52c6144ae6001600160a01b038716612fa8565b6144b857856144ba565b845b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060006040518083038186803b15801561450057600080fd5b505afa158015614514573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561453d57600080fd5b8101908080516040519392919084600160201b82111561455c57600080fd5b90830190602082018581111561457157600080fd5b82518660208202830111600160201b8211171561458d57600080fd5b82525081516020918201928201910280838360005b838110156145ba5781810151838201526020016145a2565b50505050905001604052505050905060008090505b81518110156146b35760f88282815181106145e657fe5b602002602001015160001c901c60bb14158015614629575081818151811061460a57fe5b60200260200101516001685a434ecd46efdcc7c760b11b031960001b14155b8015614654575081818151811061463c57fe5b6020026020010151600161543360e81b031960001b14155b8015614689575081818151811061466757fe5b602002602001015160016b2c2466af65a2f7eba2a7a463609a1b031960001b14155b156146ab5781818151811061469a57fe5b602002602001015192505050612fa2565b6001016145cf565b506000949350505050565b6000612f9f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614a1e565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261127c908590614a78565b600081836147e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156147ab578181015183820152602001614793565b50505050905090810190601f1680156147d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816147f257fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526133aa908490614a78565b8015806148d4575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b1580156148a657600080fd5b505afa1580156148ba573d6000803e3d6000fd5b505050506040513d60208110156148d057600080fd5b5051155b61490f5760405162461bcd60e51b8152600401808060200182810382526036815260200180614d946036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526133aa908490614a78565b60008061497d6001600160a01b0386168763ffffffff6130f316565b9050600061499a6001600160a01b0386168863ffffffff6130f316565b905060006149b0856103e563ffffffff61319d16565b905060006149c4828463ffffffff61319d16565b905060006149ea836149de876103e863ffffffff61319d16565b9063ffffffff612f4516565b90508015614a0757614a02828263ffffffff6131f616565b614a0a565b60005b9a9950505050505050505050565b16151590565b60008184841115614a705760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156147ab578181015183820152602001614793565b505050900390565b614a8a826001600160a01b0316614c30565b614adb576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614b195780518252601f199092019160209182019101614afa565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614b7b576040519150601f19603f3d011682016040523d82523d6000602084013e614b80565b606091505b509150915081614bd7576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561127c57808060200190516020811015614bf357600080fd5b505161127c5760405162461bcd60e51b815260040180806020018281038252602a815260200180614d6a602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590614c6457508115155b949350505050565b604051806103e00160405280601f905b614c95815260200190600190039081614c7c5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a723158203ce6424499244d5df6d946ff1e1427463472a95150dd93d28a25f4ce749fd82864736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f5
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x4CE45D9E8DD0dAA59DBA328AE3e01b13f93B79F5
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f5
Deployed Bytecode Sourcemap
103436:24146:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103739:10;103753:9;103739:23;;103731:32;;;;;;103436:24146;103779:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;103779:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;103779: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;103779:515:0;;;;;;;;;;;;;;;;;;104302:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;104302:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;104302: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;104302:627:0;;;;;;;;;;;;;;;;;;;104937:2961;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;104937:2961:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;104937:2961:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;104937:2961: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;104937:2961:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;104937:2961:0;;-1:-1:-1;;104937:2961:0;;;-1:-1:-1;104937:2961:0;;-1:-1:-1;;104937:2961:0:i;:::-;;;;;;;;;;;;;;;;103488:33;;8:9:-1;5:2;;;30:1;27;20:12;5:2;103488:33:0;;;:::i;:::-;;;;-1:-1:-1;;;;;103488:33:0;;;;;;;;;;;;;;103779:515;104001:20;104036:29;104126:160;104165:9;104189;104213:6;104234:5;104254;104274:1;104126:24;:160::i;:::-;104093:193;;;;-1:-1:-1;103779:515:0;;-1:-1:-1;;;;;;;103779:515:0:o;104302:627::-;104580:20;104719:12;;:202;;;-1:-1:-1;;;104719:202:0;;-1:-1:-1;;;;;104719:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104580:20;;104655:29;;104719:12;;:37;;:202;;;;;104580:20;;104719:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;104719:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;104719:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;104719: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;104719: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;104719:202:0;;421:4:-1;412:14;;;;104719:202:0;;;;;412:14:-1;104719: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;104719:202:0;;;;;;;;;;;104712:209;;;;;;104302:627;;;;;;;;;;:::o;104937:2961::-;105187:20;105237:9;-1:-1:-1;;;;;105224:22:0;:9;-1:-1:-1;;;;;105224:22:0;;105220:68;;;-1:-1:-1;105270:6:0;105263:13;;105220:68;105300;;:::i;:::-;:1049;;;;;;;;105386:14;105300:1049;;;;105415:14;105300:1049;;;;105444:13;105300:1049;;;;105472:12;105300:1049;;;;105499:20;105300:1049;;;;105534:16;105300:1049;;;;105565:13;105300:1049;;;;105593:19;105300:1049;;;;105627:21;105300:1049;;;;105663:22;105300:1049;;;;105700:18;105300:1049;;;;105733:18;105300:1049;;;;105766:16;105300:1049;;;;105797:16;105300:1049;;;;105828:19;105300:1049;;;;105862:19;105300:1049;;;;105896:20;105300:1049;;;;105931:15;105300:1049;;;;105961:18;105300:1049;;;;105994:16;105300:1049;;;;106025:17;105300:1049;;;;106057:12;105300:1049;;;;106084:18;105300:1049;;;;106117:16;105300:1049;;;;106148:16;105300:1049;;;;106179:16;105300:1049;;;;106210:16;105300:1049;;;;106241:13;105300:1049;;;;106269:13;105300:1049;;;;106297:13;105300:1049;;;;106325:13;105300:1049;;;;;106393:15;106370:12;:19;:38;;106362:117;;;;-1:-1:-1;;;106362:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;106492:13;;;106559:206;106580:12;:19;106576:1;:23;106559:206;;;106643:1;106625:12;106638:1;106625:15;;;;;;;;;;;;;;:19;106621:133;;;106673:26;106683:12;106696:1;106683:15;;;;;;;;;;;;;;106673:5;:9;;:26;;;;:::i;:::-;106665:34;;106737:1;106718:20;;106621:133;106601:3;;106559:206;;;-1:-1:-1;106781:10:0;106777:193;;106812:17;:9;-1:-1:-1;;;;;106812:15:0;;:17::i;:::-;106808:123;;;106850:30;;:10;;106870:9;106850:30;;;;;;;;;106870:9;106850:10;:30;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;106850:30:0;106906:9;106899:16;;;;;;;106808:123;106952:6;106945:13;;;;;;;106777:193;106982:66;-1:-1:-1;;;;;106982:31:0;;107014:10;107034:4;107041:6;106982:66;:31;:66;:::i;:::-;107059:23;107085:43;-1:-1:-1;;;;;107085:28:0;;107122:4;107085:43;:28;:43;:::i;:::-;107059:69;-1:-1:-1;107146:6:0;107141:433;107162:12;:19;107158:1;:23;107141:433;;;107207:12;107220:1;107207:15;;;;;;;;;;;;;;107226:1;107207:20;107203:69;;;107248:8;;107203:69;107288:18;107309:38;107341:5;107309:27;107320:12;107333:1;107320:15;;;;;;;;;;;;;;107309:6;:10;;:27;;;;:::i;:::-;:31;:38;:31;:38;:::i;:::-;107288:59;;107371:16;107366:1;:21;107362:90;;;-1:-1:-1;107421:15:0;107362:90;107485:10;107466:29;;;;107510:52;107522:9;107533;107544:10;107556:5;107510:8;107519:1;107510:11;;;;;;;;;;;:52;;:::i;:::-;107141:433;;107183:3;;107141:433;;;-1:-1:-1;107601:43:0;-1:-1:-1;;;;;107601:28:0;;107638:4;107601:43;:28;:43;:::i;:::-;107586:58;;107679:9;107663:12;:25;;107655:76;;;;-1:-1:-1;;;107655:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107742:53;-1:-1:-1;;;;;107742:27:0;;107770:10;107782:12;107742:53;:27;:53;:::i;:::-;-1:-1:-1;107806:84:0;107834:10;107846:43;-1:-1:-1;;;;;107846:28:0;;107883:4;107846:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;107806:27:0;;;:84;;:27;:84;:::i;:::-;;104937:2961;;;;;;;;;;;;;:::o;103488:33::-;;;-1:-1:-1;;;;;103488:33:0;;:::o;114785:859::-;114966:6;114990:17;-1:-1:-1;;;;;114990:15:0;;;:17::i;:::-;114985:361;;115056:37;;;-1:-1:-1;;;115056:37:0;;-1:-1:-1;;;;;115056:37:0;;;;;;;;115024:29;;49949:42;;115056:26;;:37;;;;;;;;;;;;;;;49949:42;115056:37;;;5:2:-1;;;;30:1;27;20:12;5:2;115056:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115056:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115056:37:0;;-1:-1:-1;;;;;;115112:35:0;;;115108:227;;115168:63;-1:-1:-1;;;;;115168:26:0;;115203:12;115218;115168:63;:26;:63;:::i;:::-;115265:54;;;-1:-1:-1;;;115265:54:0;;;;;;;;115312:1;115265:54;;;;115315:3;115265:54;;;;;;-1:-1:-1;;;;;115265:32:0;;;;;:54;;;;;;;;;;;;;;-1:-1:-1;115265:32:0;:54;;;5:2:-1;;;;30:1;27;20:12;5:2;115265:54:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115265:54:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115265:54:0;;-1:-1:-1;115108:227:0;114985:361;;115363:17;:9;-1:-1:-1;;;;;115363:15:0;;:17::i;:::-;115358:279;;115427:37;;;-1:-1:-1;;;115427:37:0;;-1:-1:-1;;;;;115427:37:0;;;;;;;;115397:27;;49949:42;;115427:26;;:37;;;;;;;;;;;;;;;49949:42;115427:37;;;5:2:-1;;;;30:1;27;20:12;5:2;115427:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115427:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115427:37:0;;-1:-1:-1;;;;;;115483:33:0;;;115479:147;;115552:10;-1:-1:-1;;;;;115552:30:0;;115589:12;115603:1;115606:3;115552:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115552:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115552:58:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115552:58:0;;-1:-1:-1;115479:147:0;115358:279;;114785:859;;;;;:::o;118492:214::-;118662:36;;;-1:-1:-1;;;118662:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;121909:625;122066:28;50090:42;-1:-1:-1;;;;;122112:32:0;;:49;;;;;;;;;;;;;-1:-1:-1;;;122112:49:0;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122112:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122112:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;122112:49:0;;-1:-1:-1;122173:21:0;50234:42;122197:36;122248:17;-1:-1:-1;;;;;122248:15:0;;;:17::i;:::-;:48;;122287:9;122248:48;;;48228:42;122248:48;122311:17;:9;-1:-1:-1;;;;;122311:15:0;;:17::i;:::-;:48;;122350:9;122311:48;;;48228:42;122311:48;122197:173;;;;;;;;;;;;;-1:-1:-1;;;;;122197:173:0;-1:-1:-1;;;;;122197:173:0;;;;;;-1:-1:-1;;;;;122197:173:0;-1:-1:-1;;;;;122197:173:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122197:173:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122197:173:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;122197:173: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;122197:173:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;-1:-1;;;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;122197:173:0;;421:4:-1;412:14;;;;122197:173:0;;;;;412:14:-1;122197:173: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;122197:173:0;;;;;;;;;;;122173:197;;122381:58;122416:13;122432:6;122381:9;-1:-1:-1;;;;;122381:26:0;;;:58;;;;;:::i;:::-;122450:13;-1:-1:-1;;;;;122450:21:0;;122478:17;:9;-1:-1:-1;;;;;122478:15:0;;:17::i;:::-;:30;;122507:1;122478:30;;;122498:6;122478:30;122510:4;122516:6;122524:1;122450:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;122450:76:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122450:76:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122450:76:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;;121909:625:0:o;122542:678::-;122702:17;:9;-1:-1:-1;;;;;122702:15:0;;:17::i;:::-;122698:78;;;-1:-1:-1;;;;;;;;;;;;;;;;122736:12:0;;122755:6;122736:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;122736:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122736:28:0;;;;;122698:78;122788:19;122810:17;:9;-1:-1:-1;;;;;122810:15:0;;:17::i;:::-;:36;;122837:9;122810:36;;;-1:-1:-1;;;;;;;;;;;122810:36:0;122788:58;-1:-1:-1;122857:61:0;-1:-1:-1;;;;;122857:29:0;;50605:42;122911:6;122857:61;:29;:61;:::i;:::-;50605:42;122929:27;122971:17;-1:-1:-1;;;;;122971:15:0;;;:17::i;:::-;:36;;122998:9;122971:36;;;-1:-1:-1;;;;;;;;;;;122971:36:0;123022:6;123043:17;:9;-1:-1:-1;;;;;123043:15:0;;:17::i;:::-;:36;;123070:9;123043:36;;;-1:-1:-1;;;;;;;;;;;123043:36:0;122929:177;;;-1:-1:-1;;;;;;122929:177:0;;;;;;;-1:-1:-1;;;;;122929:177:0;;;;;;;;;;;;;;;;;;;;123094:1;122929:177;;;;;;;;;;;;;;;;;;;;-1:-1:-1;122929:177:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;122929:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;122929:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;123123:17:0;;-1:-1:-1;;;;;;123123:15:0;;;:17::i;:::-;123119:94;;;123171:29;;;-1:-1:-1;;;123171:29:0;;123194:4;123171:29;;;;;;-1:-1:-1;;;;;;;;;;;48315:42:0;123157:13;;48315:42;;123171:14;;:29;;;;;;;;;;;;;;48315:42;123171:29;;;5:2:-1;;;;30:1;27;20:12;5:2;123171:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123171:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;123171:29:0;123157:44;;;-1:-1:-1;;;;;;123157:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;123157:44:0;;;;;;;-1:-1:-1;123157:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;123157:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123157:44:0;;;;122542:678;;;;;:::o;107929:522::-;108093:8;-1:-1:-1;;;;;108134:17:0;;-1:-1:-1;;;;;;;;;;;108134:17:0;:25;;108158:1;108134:25;;;108154:1;108134:25;-1:-1:-1;;;;;108105:16:0;;-1:-1:-1;;;;;;;;;;;108105:16:0;:24;;108128:1;108105:24;;;108124:1;108105:24;108104:56;108093:67;;;-1:-1:-1;108171:8:0;-1:-1:-1;;;;;;;;;;;;;;;;108212:17:0;;;:25;;108236:1;108212:25;;;108232:1;108212:25;-1:-1:-1;;;;;108183:16:0;;-1:-1:-1;;;;;;;;;;;108183:16:0;:24;;108206:1;108183:24;;;108202:1;108183:24;108182:56;108171:67;;;;108253:1;:6;;108258:1;108253:6;:16;;;;108263:1;:6;;108268:1;108263:6;108253:16;108249:55;;;108286:7;;;;108249:55;108316:58;-1:-1:-1;;;;;108316:26:0;;50703:42;108367:6;108316:58;:26;:58;:::i;:::-;108385;;;-1:-1:-1;;;108385:58:0;;-1:-1:-1;;108419:5:0;;;108385:58;;;;;;;;;;108426:5;;;108385:58;;;;;;;;;;;;;;108441:1;108385:58;;;;;;;;50703:42;;108385:33;;:58;;;;;;;;;;;108441:1;50703:42;108385:58;;;5:2:-1;;;;30:1;27;20:12;5:2;108385:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108385:58:0;;;;107929:522;;;;;;;:::o;108459:622::-;108619:8;-1:-1:-1;;;;;108716:17:0;;48668:42;108716:17;:25;;108740:1;108716:25;;;108736:1;108716:25;-1:-1:-1;;;;;108673:17:0;;-1:-1:-1;;;;;;;;;;;108673:17:0;:25;;108697:1;108673:25;;;108693:1;108673:25;-1:-1:-1;;;;;108631:16:0;;-1:-1:-1;;;;;;;;;;;108631:16:0;:24;;108654:1;108631:24;;;108650:1;108631:24;108630:69;:112;108619:123;;;;108753:8;48668:42;-1:-1:-1;;;;;108850:17:0;:9;-1:-1:-1;;;;;108850:17:0;;:25;;108874:1;108850:25;;;108870:1;108850:25;-1:-1:-1;;;;;108807:17:0;;-1:-1:-1;;;;;;;;;;;108807:17:0;:25;;108831:1;108807:25;;;108827:1;108807:25;-1:-1:-1;;;;;108765:16:0;;-1:-1:-1;;;;;;;;;;;108765:16:0;:24;;108788:1;108765:24;;;108784:1;108765:24;108764:69;:112;108753:123;;;;108891:1;:6;;108896:1;108891:6;:16;;;;108901:1;:6;;108906:1;108901:6;108891:16;108887:55;;;108924:7;;;;108887:55;108954:54;-1:-1:-1;;;;;108954:26:0;;50797:42;109001:6;108954:54;:26;:54;:::i;:::-;109019;;;-1:-1:-1;;;109019:54:0;;-1:-1:-1;;109049:5:0;;;109019:54;;;;;;;;;;109056:5;;;109019:54;;;;;;;;;;;;;;109071:1;109019:54;;;;;;;;50797:42;;109019:29;;:54;;;;;;;;;;;109071:1;50797:42;109019:54;;;5:2:-1;;;;30:1;27;20:12;109089:699:0;109246:8;-1:-1:-1;;;;;109386:17:0;;48757:42;109386:17;:25;;109410:1;109386:25;;;109406:1;109386:25;-1:-1:-1;;;;;109343:17:0;;48668:42;109343:17;:25;;109367:1;109343:25;;;109363:1;109343:25;-1:-1:-1;;;;;109300:17:0;;-1:-1:-1;;;;;;;;;;;109300:17:0;:25;;109324:1;109300:25;;;109320:1;109300:25;-1:-1:-1;;;;;109258:16:0;;-1:-1:-1;;;;;;;;;;;109258:16:0;:24;;109281:1;109258:24;;;109277:1;109258:24;109257:69;:112;:155;109246:166;;;;109423:8;48757:42;-1:-1:-1;;;;;109563:17:0;:9;-1:-1:-1;;;;;109563:17:0;;:25;;109587:1;109563:25;;;109583:1;109563:25;-1:-1:-1;;;;;109520:17:0;;48668:42;109520:17;:25;;109544:1;109520:25;;;109540:1;109520:25;-1:-1:-1;;;;;109477:17:0;;-1:-1:-1;;;;;;;;;;;109477:17:0;:25;;109501:1;109477:25;;;109497:1;109477:25;-1:-1:-1;;;;;109435:16:0;;-1:-1:-1;;;;;;;;;;;109435:16:0;:24;;109458:1;109435:24;;;109454:1;109435:24;109434:69;:112;:155;109423:166;;;;109604:1;:6;;109609:1;109604:6;:16;;;;109614:1;:6;;109619:1;109614:6;109604:16;109600:55;;;109637:7;;;;109600:55;109667:51;-1:-1:-1;;;;;109667:26:0;;50888:42;109711:6;109667:51;:26;:51;:::i;:::-;109729;;;-1:-1:-1;;;109729:51:0;;-1:-1:-1;;109756:5:0;;;109729:51;;;;;;;;;;109763:5;;;109729:51;;;;;;;;;;;;;;109778:1;109729:51;;;;;;;;50888:42;;109729:26;;:51;;;;;;;;;;;109778:1;50888:42;109729:51;;;5:2:-1;;;;30:1;27;20:12;109796:717:0;109959:8;-1:-1:-1;;;;;110099:17:0;;48846:42;110099:17;:25;;110123:1;110099:25;;;110119:1;110099:25;-1:-1:-1;;;;;110056:17:0;;48668:42;110056:17;:25;;110080:1;110056:25;;;110076:1;110056:25;-1:-1:-1;;;;;110013:17:0;;-1:-1:-1;;;;;;;;;;;110013:17:0;:25;;110037:1;110013:25;;;110033:1;110013:25;-1:-1:-1;;;;;109971:16:0;;-1:-1:-1;;;;;;;;;;;109971:16:0;:24;;109994:1;109971:24;;;109990:1;109971:24;109970:69;:112;:155;109959:166;;;;110136:8;48846:42;-1:-1:-1;;;;;110276:17:0;:9;-1:-1:-1;;;;;110276:17:0;;:25;;110300:1;110276:25;;;110296:1;110276:25;-1:-1:-1;;;;;110233:17:0;;48668:42;110233:17;:25;;110257:1;110233:25;;;110253:1;110233:25;-1:-1:-1;;;;;110190:17:0;;-1:-1:-1;;;;;;;;;;;110190:17:0;:25;;110214:1;110190:25;;;110210:1;110190:25;-1:-1:-1;;;;;110148:16:0;;-1:-1:-1;;;;;;;;;;;110148:16:0;:24;;110171:1;110148:24;;;110167:1;110148:24;110147:69;:112;:155;110136:166;;;;110317:1;:6;;110322:1;110317:6;:16;;;;110327:1;:6;;110332:1;110327:6;110317:16;110313:55;;;110350:7;;;;110313:55;110380:57;-1:-1:-1;;;;;110380:26:0;;50985:42;110430:6;110380:57;:26;:57;:::i;:::-;110448;;;-1:-1:-1;;;110448:57:0;;-1:-1:-1;;110481:5:0;;;110448:57;;;;;;;;;;110488:5;;;110448:57;;;;;;;;;;;;;;110503:1;110448:57;;;;;;;;50985:42;;110448:32;;:57;;;;;;;;;;;110503:1;50985:42;110448:57;;;5:2:-1;;;;30:1;27;20:12;110521:723:0;110686:8;-1:-1:-1;;;;;110826:17:0;;48935:42;110826:17;:25;;110850:1;110826:25;;;110846:1;110826:25;-1:-1:-1;;;;;110783:17:0;;48668:42;110783:17;:25;;110807:1;110783:25;;;110803:1;110783:25;-1:-1:-1;;;;;110740:17:0;;-1:-1:-1;;;;;;;;;;;110740:17:0;:25;;110764:1;110740:25;;;110760:1;110740:25;-1:-1:-1;;;;;110698:16:0;;-1:-1:-1;;;;;;;;;;;110698:16:0;:24;;110721:1;110698:24;;;110717:1;110698:24;110697:69;:112;:155;110686:166;;;;110863:8;48935:42;-1:-1:-1;;;;;111003:17:0;:9;-1:-1:-1;;;;;111003:17:0;;:25;;111027:1;111003:25;;;111023:1;111003:25;-1:-1:-1;;;;;110960:17:0;;48668:42;110960:17;:25;;110984:1;110960:25;;;110980:1;110960:25;-1:-1:-1;;;;;110917:17:0;;-1:-1:-1;;;;;;;;;;;110917:17:0;:25;;110941:1;110917:25;;;110937:1;110917:25;-1:-1:-1;;;;;110875:16:0;;-1:-1:-1;;;;;;;;;;;110875:16:0;:24;;110898:1;110875:24;;;110894:1;110875:24;110874:69;:112;:155;110863:166;;;;111044:1;:6;;111049:1;111044:6;:16;;;;111054:1;:6;;111059:1;111054:6;111044:16;111040:55;;;111077:7;;;;111040:55;111107:59;-1:-1:-1;;;;;111107:26:0;;51084:42;111159:6;111107:59;:26;:59;:::i;:::-;111177;;;-1:-1:-1;;;111177:59:0;;-1:-1:-1;;111212:5:0;;;111177:59;;;;;;;;;;111219:5;;;111177:59;;;;;;;;;;;;;;111234:1;111177:59;;;;;;;;51084:42;;111177:34;;:59;;;;;;;;;;;111234:1;51084:42;111177:59;;;5:2:-1;;;;30:1;27;20:12;115652:921:0;115819:17;:9;-1:-1:-1;;;;;115819:15:0;;:17::i;:::-;115814:380;;115883:41;;;-1:-1:-1;;;115883:41:0;;-1:-1:-1;;;;;115883:41:0;;;;;;;;115853:27;;52920:42;;115883:30;;:41;;;;;;;;;;;;;;;52920:42;115883:41;;;5:2:-1;;;;30:1;27;20:12;5:2;115883:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;115883:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;115883:41:0;;-1:-1:-1;115939:57:0;-1:-1:-1;;;;;115939:26:0;;115883:41;115989:6;115939:57;:26;:57;:::i;:::-;116011:12;-1:-1:-1;;;;;116011:17:0;;116029:6;116011:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116011:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116011:25:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116051:110:0;;-1:-1:-1;116073:12:0;116088:9;116099:54;-1:-1:-1;;;;;116099:39:0;;116147:4;116099:54;:39;:54;:::i;:::-;116155:5;116051:14;:110::i;:::-;116176:7;;;115814:380;116211:17;:9;-1:-1:-1;;;;;116211:15:0;;:17::i;:::-;116206:360;;116273:41;;;-1:-1:-1;;;116273:41:0;;-1:-1:-1;;;;;116273:41:0;;;;;;;;116245:25;;52920:42;;116273:30;;:41;;;;;;;;;;;;;;;52920:42;116273:41;;;5:2:-1;;;;30:1;27;20:12;5:2;116273:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116273:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116273:41:0;;-1:-1:-1;116329:60:0;116344:9;116273:41;116375:6;116383:5;116329:14;:60::i;:::-;-1:-1:-1;;;;;116404:17:0;;;116422:52;116404:17;116468:4;116422:52;:37;:52;:::i;:::-;116404:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;116404:71:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;116404:71:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;116490:43:0;;-1:-1:-1;;;;;;116490:28:0;;116527:4;116490:43;:28;:43;:::i;:::-;;116548:7;;;116581:646;-1:-1:-1;;;;;116743:16:0;;-1:-1:-1;;;;;;;;;;;116743:16:0;116739:275;;;116776:49;-1:-1:-1;;;;;116776:26:0;;48402:42;116818:6;116776:49;:26;:49;:::i;:::-;116840:32;;;-1:-1:-1;;;116840:32:0;;116858:4;116840:32;;;;;;;;;;;;48402:42;;116840:9;;:32;;;;;-1:-1:-1;;116840:32:0;;;;;;;-1:-1:-1;48402:42:0;116840:32;;;5:2:-1;;;;30:1;27;20:12;5:2;116840:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;116887:94:0;;-1:-1:-1;48402:42:0;;-1:-1:-1;116916:9:0;;-1:-1:-1;116927:46:0;48402:42;116967:4;116927:46;:31;:46;:::i;:::-;116975:5;116887:14;:94::i;:::-;116996:7;;116739:275;-1:-1:-1;;;;;117030:16:0;;-1:-1:-1;;;;;;;;;;;117030:16:0;117026:194;;;117063:54;117078:9;48402:42;117103:6;117111:5;117063:14;:54::i;:::-;117157:29;;;-1:-1:-1;;;117157:29:0;;117150:4;117157:29;;;;;;;;48402:42;;117132:9;;117150:4;;48402:42;;117157:14;;:29;;;;;;;;;;;;;;48402:42;117157:29;;;5:2:-1;;;;30:1;27;20:12;5:2;117157:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117157:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117157:29:0;117132:55;;;-1:-1:-1;;;;;;117132:55:0;;;;;;;-1:-1:-1;;;;;117132:55:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;117132:55:0;;;;;;;-1:-1:-1;117132:55:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;117132:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117132:55:0;;;;117202:7;;117235:800;117398:17;:9;-1:-1:-1;;;;;117398:15:0;;:17::i;:::-;117393:362;;117454:37;;;-1:-1:-1;;;117454:37:0;;-1:-1:-1;;;;;117454:37:0;;;;;;;;117432:19;;53031:42;;117454:26;;:37;;;;;;;;;;;;;;;53031:42;117454:37;;;5:2:-1;;;;30:1;27;20:12;5:2;117454:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117454:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117454:37:0;117533:11;;;-1:-1:-1;;;117533:11:0;;;;117454:37;;-1:-1:-1;117506:47:0;;51660:42;;117533:9;;:11;;;;;117454:37;;117533:11;;;;;;;51660:42;117533:11;;;5:2:-1;;;;30:1;27;20:12;5:2;117533:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117533:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117533:11:0;-1:-1:-1;;;;;117506:26:0;;;117546:6;117506:47;:26;:47;:::i;:::-;117568:37;;;-1:-1:-1;;;117568:37:0;;-1:-1:-1;;;;;117568:37:0;;;;;;;;;;;;117600:4;117568:37;;;;;;51660:42;;117568:12;;:37;;;;;-1:-1:-1;;117568:37:0;;;;;;;-1:-1:-1;51660:42:0;117568:37;;;5:2:-1;;;;30:1;27;20:12;5:2;117568:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117568:37:0;;;;117620:102;117642:8;117653:9;117664:50;117708:4;117671:8;-1:-1:-1;;;;;117664:35:0;;;:50;;;;:::i;117393:362::-;117772:17;:9;-1:-1:-1;;;;;117772:15:0;;:17::i;:::-;117767:261;;117826:37;;;-1:-1:-1;;;117826:37:0;;-1:-1:-1;;;;;117826:37:0;;;;;;;;117806:17;;53031:42;;117826:26;;:37;;;;;;;;;;;;;;;53031:42;117826:37;;;5:2:-1;;;;30:1;27;20:12;5:2;117826:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117826:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117826:37:0;;-1:-1:-1;117878:56:0;117893:9;117826:37;117920:6;117928:5;117878:14;:56::i;:::-;117963:31;;;-1:-1:-1;;;117963:31:0;;117988:4;117963:31;;;;;;-1:-1:-1;;;;;117949:13:0;;;;;;;117963:16;;:31;;;;;;;;;;;;;;117949:13;117963:31;;;5:2:-1;;;;30:1;27;20:12;5:2;117963:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117963:31:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117963:31:0;117949:46;;;-1:-1:-1;;;;;;117949:46:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;117949:46:0;;;;;;;-1:-1:-1;117949:46:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;117949:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117949:46:0;;;;118010:7;;;118043:441;118203:20;51990:42;-1:-1:-1;;;;;118226:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;118226:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118226:26:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118226:26:0;;-1:-1:-1;118263:54:0;-1:-1:-1;;;;;118263:26:0;;118226;118310:6;118263:54;:26;:54;:::i;:::-;118328:9;-1:-1:-1;;;;;118328:14:0;;118349:17;:9;-1:-1:-1;;;;;118349:15:0;;:17::i;:::-;:30;;118378:1;118349:30;;;118369:6;118349:30;118328:148;;;-1:-1:-1;;;;;;118328:148:0;;;;;;;-1:-1:-1;;;;;118328:148:0;;;;;;;;;;;;;;;;;;;118464:1;118328:148;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;118328:148:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;118328:148:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;118043:441:0:o;124704:288::-;124860:124;124899:9;124923;124947:6;124968:5;124860:24;:124::i;125000:309::-;125159:142;125197:9;-1:-1:-1;;;;;;;;;;;125240:9:0;125264:6;125285:5;125159:23;:142::i;125317:308::-;125476:141;125514:9;-1:-1:-1;;;;;;;;;;;125556:9:0;125580:6;125601:5;125476:23;:141::i;125633:310::-;125793:142;125831:9;-1:-1:-1;;;;;;;;;;;125874:9:0;125898:6;125919:5;125793:23;:142::i;111252:703::-;111411:8;-1:-1:-1;;;;;111551:16:0;;49023:42;111551:16;:24;;111574:1;111551:24;;;111570:1;111551:24;-1:-1:-1;;;;;111508:17:0;;48668:42;111508:17;:25;;111532:1;111508:25;;;111528:1;111508:25;-1:-1:-1;;;;;111465:17:0;;-1:-1:-1;;;;;;;;;;;111465:17:0;:25;;111489:1;111465:25;;;111485:1;111465:25;-1:-1:-1;;;;;111423:16:0;;-1:-1:-1;;;;;;;;;;;111423:16:0;:24;;111446:1;111423:24;;;111442:1;111423:24;111422:69;:112;:154;111411:165;;;;111587:8;49023:42;-1:-1:-1;;;;;111727:16:0;:9;-1:-1:-1;;;;;111727:16:0;;:24;;111750:1;111727:24;;;111746:1;111727:24;-1:-1:-1;;;;;111684:17:0;;48668:42;111684:17;:25;;111708:1;111684:25;;;111704:1;111684:25;-1:-1:-1;;;;;111641:17:0;;-1:-1:-1;;;;;;;;;;;111641:17:0;:25;;111665:1;111641:25;;;111661:1;111641:25;-1:-1:-1;;;;;111599:16:0;;-1:-1:-1;;;;;;;;;;;111599:16:0;:24;;111622:1;111599:24;;;111618:1;111599:24;111598:69;:112;:154;111587:165;;;;111767:1;:6;;111772:1;111767:6;:16;;;;111777:1;:6;;111782:1;111777:6;111767:16;111763:55;;;111800:7;;;;111763:55;111830:53;-1:-1:-1;;;;;111830:26:0;;51177:42;111876:6;111830:53;:26;:53;:::i;:::-;111894;;;-1:-1:-1;;;111894:53:0;;-1:-1:-1;;111923:5:0;;;111894:53;;;;;;;;;;111930:5;;;111894:53;;;;;;;;;;;;;;111945:1;111894:53;;;;;;;;51177:42;;111894:28;;:53;;;;;;;;;;;111945:1;51177:42;111894:53;;;5:2:-1;;;;30:1;27;20:12;112706:537:0;112868:8;-1:-1:-1;;;;;112925:17:0;;49203:42;112925:17;:25;;112949:1;112925:25;;;112945:1;112925:25;-1:-1:-1;;;;;112880:19:0;;49114:42;112880:19;:27;;112906:1;112880:27;;;112902:1;112880:27;112879:72;112868:83;;;-1:-1:-1;112962:8:0;49203:42;-1:-1:-1;;;;;113019:17:0;;;:25;;113043:1;113019:25;;;113039:1;113019:25;-1:-1:-1;;;;;112974:19:0;;49114:42;112974:19;:27;;113000:1;112974:27;;;112996:1;112974:27;112973:72;112962:83;;;;113060:1;:6;;113065:1;113060:6;:16;;;;113070:1;:6;;113075:1;113070:6;113060:16;113056:55;;;113093:7;;;;113056:55;113123:56;-1:-1:-1;;;;;113123:26:0;;51273:42;113172:6;113123:56;:26;:56;:::i;:::-;113190:45;;;-1:-1:-1;;;113190:45:0;;-1:-1:-1;;113211:5:0;;;113190:45;;;;;;;;;;113218:5;;;113190:45;;;;;;;;;;;;;;113233:1;113190:45;;;;;;;;51273:42;;113190:20;;:45;;;;;;;;;;;113233:1;51273:42;113190:45;;;5:2:-1;;;;30:1;27;20:12;113251:613:0;113411:8;-1:-1:-1;;;;;113509:17:0;;49381:42;113509:17;:25;;113533:1;113509:25;;;113529:1;113509:25;-1:-1:-1;;;;;113466:17:0;;49203:42;113466:17;:25;;113490:1;113466:25;;;113486:1;113466:25;-1:-1:-1;;;;;113423:17:0;;49292:42;113423:17;:25;;113447:1;113423:25;;;113443:1;113423:25;113422:70;:113;113411:124;;;;113546:8;49381:42;-1:-1:-1;;;;;113644:17:0;:9;-1:-1:-1;;;;;113644:17:0;;:25;;113668:1;113644:25;;;113664:1;113644:25;-1:-1:-1;;;;;113601:17:0;;49203:42;113601:17;:25;;113625:1;113601:25;;;113621:1;113601:25;-1:-1:-1;;;;;113558:17:0;;49292:42;113558:17;:25;;113582:1;113558:25;;;113578:1;113558:25;113557:70;:113;113546:124;;;;113685:1;:6;;113690:1;113685:6;:16;;;;113695:1;:6;;113700:1;113695:6;113685:16;113681:55;;;113718:7;;;;113681:55;113748:54;-1:-1:-1;;;;;113748:26:0;;51367:42;113795:6;113748:54;:26;:54;:::i;:::-;113813:43;;;-1:-1:-1;;;113813:43:0;;-1:-1:-1;;113832:5:0;;;113813:43;;;;;;;;;;113839:5;;;113813:43;;;;;;;;;;;;;;113854:1;113813:43;;;;;;;;51367:42;;113813:18;;:43;;;;;;;;;;;113854:1;51367:42;113813:43;;;5:2:-1;;;;30:1;27;20:12;114497:280:0;114658:55;-1:-1:-1;;;;;114658:26:0;;52211:42;114706:6;114658:55;:26;:55;:::i;:::-;114724:45;;;-1:-1:-1;;;114724:45:0;;-1:-1:-1;;;;;114724:45:0;;;;;;;;;;;;;;;;;;;;;52211:42;;114724:15;;:45;;;;;-1:-1:-1;;114724:45:0;;;;;;;-1:-1:-1;52211:42:0;114724:45;;;5:2:-1;;;;30:1;27;20:12;5:2;114724:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;111963:380:0;112119:50;-1:-1:-1;;;;;112119:26:0;;51551:42;112162:6;112119:50;:26;:50;:::i;:::-;112180:155;;;-1:-1:-1;;;112180:155:0;;-1:-1:-1;;;;;112180:155:0;;;;;;;;;;;;;;;;;;;112300:1;112180:155;;;;;;112322:2;112316:3;:8;112180:155;;;;;;51551:42;;112180:18;;:155;;;;;;;;;;;;;;;;;;51551:42;112180:155;;;5:2:-1;;;;30:1;27;20:12;5:2;112180:155:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;112180:155:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;112351:347:0;112513:49;-1:-1:-1;;;;;112513:26:0;;52304:42;112555:6;112513:49;:26;:49;:::i;:::-;112573:117;;;-1:-1:-1;;;112573:117:0;;-1:-1:-1;;;;;112573:117:0;;;;;;;;;;;;;;;;;;;112674:4;112573:117;;;;;;52304:42;;112573:9;;:117;;;;;;;;;;;;;;-1:-1:-1;52304:42:0;112573:117;;;5:2:-1;;;;30:1;27;20:12;113872:617:0;114032:8;-1:-1:-1;;;;;114132:17:0;;49470:42;114132:17;:25;;114156:1;114132:25;;;114152:1;114132:25;-1:-1:-1;;;;;114089:17:0;;49203:42;114089:17;:25;;114113:1;114089:25;;;114109:1;114089:25;-1:-1:-1;;;;;114044:19:0;;49114:42;114044:19;:27;;114070:1;114044:27;;;114066:1;114044:27;114043:72;:115;114032:126;;;;114169:8;49470:42;-1:-1:-1;;;;;114269:17:0;:9;-1:-1:-1;;;;;114269:17:0;;:25;;114293:1;114269:25;;;114289:1;114269:25;-1:-1:-1;;;;;114226:17:0;;49203:42;114226:17;:25;;114250:1;114226:25;;;114246:1;114226:25;-1:-1:-1;;;;;114181:19:0;;49114:42;114181:19;:27;;114207:1;114181:27;;;114203:1;114181:27;114180:72;:115;114169:126;;;;114310:1;:6;;114315:1;114310:6;:16;;;;114320:1;:6;;114325:1;114320:6;114310:16;114306:55;;;114343:7;;;;114306:55;114373:54;-1:-1:-1;;;;;114373:26:0;;51461:42;114420:6;114373:54;:26;:54;:::i;:::-;114438:43;;;-1:-1:-1;;;114438:43:0;;-1:-1:-1;;114457:5:0;;;114438:43;;;;;;;;;;114464:5;;;114438:43;;;;;;;;;;;;;;114479:1;114438:43;;;;;;;;51461:42;;114438:18;;:43;;;;;;;;;;;114479:1;51461:42;114438:43;;;5:2:-1;;;;30:1;27;20:12;126903:220:0;127059:56;127076:9;127087;127098:6;127106:5;127113:1;127059:16;:56::i;127131:220::-;127287:56;127304:9;127315;127326:6;127334:5;127341:1;127287:16;:56::i;127359:220::-;127515:56;127532:9;127543;127554:6;127562:5;127569:1;127515:16;:56::i;118714:354::-;118867:193;118894:9;118918;118942:6;118963:5;-1:-1:-1;;;;;;118867:12:0;:193::i;119076:354::-;119229:193;119256:9;119280;119304:6;119325:5;-1:-1:-1;;;;;;119229:12:0;:193::i;119438:354::-;119591:193;119618:9;119642;119666:6;119687:5;-1:-1:-1;;;;;;119591:12:0;:193::i;119800:333::-;119953:172;119980:9;120004;120028:6;120049:5;120069:45;120093:9;120104;120069:23;:45::i;:::-;119953:12;:172::i;12251:181::-;12309:7;12341:5;;;12365:6;;;;12357:46;;;;;-1:-1:-1;;;12357:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;12423:1;-1:-1:-1;12251:181:0;;;;;:::o;40604:166::-;40655:4;-1:-1:-1;;;;;40680:39:0;;;;:81;;-1:-1:-1;;;;;;40723:38:0;;37776:42;40723:38;40672:90;40604:166;-1:-1:-1;;40604:166:0:o;38184:617::-;38295:11;38291:50;;38323:7;;38291:50;38357:12;38363:5;38357;:12::i;:::-;38353:441;;;-1:-1:-1;;;;;38394:18:0;;38402:10;38394:18;:41;;;;;38429:6;38416:9;:19;;38394:41;38386:97;;;;-1:-1:-1;;;38386:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;38502:19:0;;38516:4;38502:19;38498:97;;38542:37;;-1:-1:-1;;;;;38542:29:0;;;:37;;;;;38572:6;;38542:37;;;;38572:6;38542:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38542:37:0;38498:97;38625:6;38613:9;:18;38609:101;;;38652:10;:42;38672:21;:9;38686:6;38672:21;:13;:21;:::i;:::-;38652:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;38353:441:0;38742:40;-1:-1:-1;;;;;38742:22:0;;38765:4;38771:2;38775:6;38742:40;:22;:40;:::i;39786:228::-;39864:7;39888:12;39894:5;39888;:12::i;:::-;39884:123;;;-1:-1:-1;;;;;;39924:11:0;;;39917:18;;39884:123;39975:5;-1:-1:-1;;;;;39975:15:0;;39991:3;39975:20;;;;;;;;;;;;;-1:-1:-1;;;;;39975:20:0;-1:-1:-1;;;;;39975:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39975:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39975:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39975:20:0;;-1:-1:-1;39968:27:0;;13623:471;13681:7;13926:6;13922:47;;-1:-1:-1;13956:1:0;13949:8;;13922:47;13993:5;;;13997:1;13993;:5;:1;14017:5;;;;;:10;14009:56;;;;-1:-1:-1;;;14009:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14562:132;14620:7;14647:39;14651:1;14654;14647:39;;;;;;;;;;;;;;;;;:3;:39::i;37828:348::-;37914:4;37935:11;37931:55;;-1:-1:-1;37970:4:0;37963:11;;37931:55;38002:12;38008:5;38002;:12::i;:::-;37998:171;;;38031:37;;-1:-1:-1;;;;;38031:29:0;;;:37;;;;;38061:6;;38031:37;;;;38061:6;38031:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38031:37:0;37998:171;;;38101:30;-1:-1:-1;;;;;38101:18:0;;38120:2;38124:6;38101:30;:18;:30;:::i;:::-;-1:-1:-1;38153:4:0;37998:171;37828:348;;;;;:::o;39260:518::-;39353:12;39359:5;39353;:12::i;:::-;39348:423;;39386:11;39382:101;;39418:24;-1:-1:-1;;;;;39418:17:0;;39436:2;39440:1;39418:24;:17;:24;:::i;:::-;39461:7;;39382:101;39519:34;;;-1:-1:-1;;;39519:34:0;;39543:4;39519:34;;;;-1:-1:-1;;;;;39519:34:0;;;;;;;;;39499:17;;39519:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;39519:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39519:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39519:34:0;;-1:-1:-1;39572:18:0;;;39568:192;;;39615:13;;39611:86;;39653:24;-1:-1:-1;;;;;39653:17:0;;39671:2;39675:1;39653:24;:17;:24;:::i;:::-;39715:29;-1:-1:-1;;;;;39715:17:0;;39733:2;39737:6;39715:29;:17;:29;:::i;39348:423::-;39260:518;;;:::o;123228:1003::-;123393:20;123430:17;:9;-1:-1:-1;;;;;123430:15:0;;:17::i;:::-;123426:78;;;-1:-1:-1;;;;;;;;;;;;;;;;123464:12:0;;123483:6;123464:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;123464:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123464:28:0;;;;;123426:78;123516:20;123539:17;:9;-1:-1:-1;;;;;123539:15:0;;:17::i;:::-;:36;;123566:9;123539:36;;;-1:-1:-1;;;;;;;;;;;123539:36:0;123516:59;;123586:18;123607:17;:9;-1:-1:-1;;;;;123607:15:0;;:17::i;:::-;:36;;123634:9;123607:36;;;-1:-1:-1;;;;;;;;;;;123607:36:0;123684:45;;;-1:-1:-1;;;123684:45:0;;-1:-1:-1;;;;;123684:45:0;;;;;;;;;;;;;;;123586:57;;-1:-1:-1;123654:27:0;;52106:42;;123684:17;;:45;;;;;;;;;;;;;;52106:42;123684:45;;;5:2:-1;;;;30:1;27;20:12;5:2;123684:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123684:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;123684:45:0;;-1:-1:-1;123755:54:0;-1:-1:-1;;;;;123755:18:0;;123774:13;123789:11;123802:6;123755:54;:18;:54;:::i;:::-;123740:69;-1:-1:-1;123822:58:0;-1:-1:-1;;;;;123822:31:0;;123862:8;123873:6;123822:58;:31;:58;:::i;:::-;;123945:11;-1:-1:-1;;;;;123929:29:0;123911:13;-1:-1:-1;;;;;123895:31:0;:63;123891:227;;;123975:49;;;-1:-1:-1;;;123975:49:0;;123989:1;123975:49;;;;;;;;;;;;124014:4;123975:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;123975:13:0;;;;;:49;;;;;;;;;;;123989:1;123975:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;123975:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;123975:49:0;;;;123891:227;;;124057:49;;;-1:-1:-1;;;124057:49:0;;;;;;;;124085:1;124057:49;;;;;;124096:4;124057:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;124057:13:0;;;;;:49;;;;;;;;;;;124085:1;124057:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;124057:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;124057:49:0;;;;123891:227;124134:17;:9;-1:-1:-1;;;;;124134:15:0;;:17::i;:::-;124130:94;;;124182:29;;;-1:-1:-1;;;124182:29:0;;124205:4;124182:29;;;;;;-1:-1:-1;;;;;;;;;;;48315:42:0;124168:13;;48315:42;;124182:14;;:29;;;;;;;;;;;;;;48315:42;124182:29;;;5:2:-1;;;;30:1;27;20:12;5:2;124182:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;124182:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;124182:29:0;124168:44;;;-1:-1:-1;;;;;;124168:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;124168:44:0;;;;;;;-1:-1:-1;124168:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;124168:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;124168:44:0;;;;124130:94;123228:1003;;;;;;;;;:::o;124239:457::-;124428:260;124467:8;124490:9;124514:143;124557:9;124585:8;124612:6;124637:5;124514:24;:143::i;:::-;124672:5;124428:24;:260::i;125951:944::-;126139:22;52563:42;126164:38;126225:17;-1:-1:-1;;;;;126225:15:0;;;:17::i;:::-;:36;;126252:9;126225:36;;;-1:-1:-1;;;;;;;;;;;126225:36:0;126285:17;:9;-1:-1:-1;;;;;126285:15:0;;:17::i;:::-;:36;;126312:9;126285:36;;;-1:-1:-1;;;;;;;;;;;126285:36:0;126337:9;126349:1;126337:13;126164:197;;;;;;;;;;;;;-1:-1:-1;;;;;126164:197:0;-1:-1:-1;;;;;126164:197:0;;;;;;-1:-1:-1;;;;;126164:197:0;-1:-1:-1;;;;;126164:197:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126164:197:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126164:197:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;126164:197:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;126164:197:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;-1:-1;;;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;126164:197:0;;421:4:-1;412:14;;;;126164:197:0;;;;;412:14:-1;126164:197:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;126164:197:0;;;;;;;;;;;126139:222;;126378:17;:9;-1:-1:-1;;;;;126378:15:0;;:17::i;:::-;126374:78;;;-1:-1:-1;;;;;;;;;;;;;;;;126412:12:0;;126431:6;126412:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126412:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126412:28:0;;;;;126374:78;126464:81;126520:5;126526:9;126520:16;;;;;;;;;;;;;;126538:6;126465:17;:9;-1:-1:-1;;;;;126465:15:0;;:17::i;:::-;:36;;126492:9;126465:36;;;-1:-1:-1;;;;;;;;;;;126465:36:0;-1:-1:-1;;;;;126464:55:0;;:81;;:55;:81;:::i;:::-;126570:5;126576:9;126570:16;;;;;;;;;;;;;;-1:-1:-1;;;;;126556:49:0;;126620:17;:9;-1:-1:-1;;;;;126620:15:0;;:17::i;:::-;:36;;126647:9;126620:36;;;-1:-1:-1;;;;;;;;;;;126620:36:0;126671:6;126692:17;:9;-1:-1:-1;;;;;126692:15:0;;:17::i;:::-;:36;;126719:9;126692:36;;;-1:-1:-1;;;;;;;;;;;126692:36:0;126743:1;-1:-1:-1;;126556:225:0;;;;;;;;;;;;;-1:-1:-1;;;;;126556:225:0;-1:-1:-1;;;;;126556:225:0;;;;;;;;;;;-1:-1:-1;;;;;126556:225:0;-1:-1:-1;;;;;126556:225:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126556:225:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126556:225:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;126798:17:0;;-1:-1:-1;;;;;;126798:15:0;;;:17::i;:::-;126794:94;;;126846:29;;;-1:-1:-1;;;126846:29:0;;126869:4;126846:29;;;;;;-1:-1:-1;;;;;;;;;;;48315:42:0;126832:13;;48315:42;;126846:14;;:29;;;;;;;;;;;;;;48315:42;126846:29;;;5:2:-1;;;;30:1;27;20:12;5:2;126846:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126846:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;126846:29:0;126832:44;;;-1:-1:-1;;;;;;126832:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;126832:44:0;;;;;;;-1:-1:-1;126832:44:0;;;;5:2:-1;;;;30:1;27;20:12;120141:1760:0;120344:6;120321:20;120375:21;:5;-1:-1:-1;;;120375:21:0;:11;:21;:::i;:::-;:30;;120404:1;120375:30;;;120399:2;120375:30;120448:16;;;120462:1;120448:16;;;;;;;;;120361:44;;;;;;-1:-1:-1;120418:27:0;;120448:16;;;;;;;105:10:-1;120448:16:0;88:34:-1;136:17;;-1:-1;120448:16:0;120418:46;;120491:9;120475:10;120486:1;120475:13;;;;;;;;;;;;;:25;;;;;120518:17;:9;-1:-1:-1;;;;;120518:15:0;;:17::i;:::-;120513:713;;120552:21;49832:42;-1:-1:-1;;;;;120576:36:0;;120631:9;120659:34;120712:10;120755:1;120741:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;120741:16:0;;120576:196;;;;;;;;;;;;;-1:-1:-1;;;;;120576:196:0;-1:-1:-1;;;;;120576:196: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;120576:196: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;120576:196:0;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120576:196:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120576:196:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;120576:196: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;120576:196:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;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;120576:196:0;;420:4:-1;411:14;;;;120576:196:0;;;;;411:14:-1;120576:196: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;120576:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;120576:196:0;;-1:-1:-1;120552:220:0;;-1:-1:-1;120789:62:0;;-1:-1:-1;;;;;;;120789:26:0;;49598:42;120844:6;120789:62;:26;:62;:::i;:::-;49598:42;-1:-1:-1;;;;;120881:37:0;;120937:9;120965:12;48103:42;121034:4;-1:-1:-1;;121088:1:0;121108:42;121169:3;121191:8;120881:333;;;;;;;;;;;;;-1:-1:-1;;;;;120881:333:0;-1:-1:-1;;;;;120881:333:0;;;;;;;;;;;-1:-1:-1;;;;;120881:333:0;-1:-1:-1;;;;;120881:333:0;;;;;;-1:-1:-1;;;;;120881:333:0;-1:-1:-1;;;;;120881:333:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;120881:333:0;-1:-1:-1;;;;;120881:333: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;120881:333:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;120881:333:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;120881:333:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;120881:333:0;;-1:-1:-1;;120513:713:0;121243:17;:9;-1:-1:-1;;;;;121243:15:0;;:17::i;:::-;121238:656;;121277:21;49832:42;-1:-1:-1;;;;;121301:36:0;;121356:9;121384:34;121437:10;121480:1;121466:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;121466:16:0;;121301:196;;;;;;;;;;;;;-1:-1:-1;;;;;121301:196:0;-1:-1:-1;;;;;121301:196: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;121301:196: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;121301:196:0;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;121301:196:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;121301:196:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;121301:196: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;121301:196:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;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;121301:196:0;;420:4:-1;411:14;;;;121301:196:0;;;;;411:14:-1;121301:196: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;121301:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121277:220;;49598:42;-1:-1:-1;;;;;121529:37:0;;121573:12;48103:42;121635:12;121666:9;121702:4;-1:-1:-1;;121756:1:0;121776:42;121837:3;121859:8;121529:353;;;;;;;;;;;;;-1:-1:-1;;;;;121529:353:0;-1:-1:-1;;;;;121529:353:0;;;;;;;;;;;-1:-1:-1;;;;;121529:353:0;-1:-1:-1;;;;;121529:353:0;;;;;;-1:-1:-1;;;;;121529:353:0;-1:-1:-1;;;;;121529:353:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;121529:353:0;-1:-1:-1;;;;;121529:353: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;121529:353:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;121529:353:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;121529:353:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;;;;;120141:1760:0:o;54895:951::-;55011:7;55036:17;:9;-1:-1:-1;;;;;55036:15:0;;:17::i;:::-;55035:18;:40;;;;;55058:17;:9;-1:-1:-1;;;;;55058:15:0;;:17::i;:::-;55057:18;55035:40;55031:81;;;-1:-1:-1;55099:1:0;55092:8;;55031:81;55124:27;49709:42;55154:37;55206:17;-1:-1:-1;;;;;55206:15:0;;;:17::i;:::-;:41;;55238:9;55206:41;;;55226:9;55206:41;55154:104;;;;;;;;;;;;;-1:-1:-1;;;;;55154:104:0;-1:-1:-1;;;;;55154:104:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;55154:104:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;55154:104:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;55154:104: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;55154:104:0;;;;;;;;;;;;;-1:-1:-1;;;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;219:3;213:10;331:9;325:2;311:12;307:21;289:16;285:44;282:59;-1:-1;;;247:12;244:29;233:116;230:2;;;362:1;359;352:12;230:2;373:25;;-1:-1;55154:104:0;;421:4:-1;412:14;;;;55154:104:0;;;;;412:14:-1;55154:104: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;55154:104:0;;;;;;;;;;;55124:134;;55276:6;55285:1;55276:10;;55271:547;55292:10;:17;55288:1;:21;55271:547;;;55362:3;55344:10;55355:1;55344:13;;;;;;;;;;;;;;55336:22;;:29;;55370:4;55335:39;;:153;;;;;55405:10;55416:1;55405:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;55405:83:0;;;;55335:153;:270;;;;;55522:10;55533:1;55522:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;55522:83:0;;;;55335:270;:387;;;;;55639:10;55650:1;55639:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;55639:83:0;;;;55335:387;55331:476;;;55778:10;55789:1;55778:13;;;;;;;;;;;;;;55771:20;;;;;;55331:476;55311:3;;55271:547;;;-1:-1:-1;55837:1:0;;54895:951;-1:-1:-1;;;;54895:951:0:o;12707:136::-;12765:7;12792:43;12796:1;12799;12792:43;;;;;;;;;;;;;;;;;:3;:43::i;34483:204::-;34610:68;;;-1:-1:-1;;;;;34610:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;34610:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;34584:95:0;;34603:5;;34584:18;:95::i;15224:345::-;15310:7;15412:12;15405:5;15397:28;;;;-1:-1:-1;;;15397:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;15397:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15436:9;15452:1;15448;:5;;;;;;;15224:345;-1:-1:-1;;;;;15224:345:0:o;34299:176::-;34408:58;;;-1:-1:-1;;;;;34408:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;34408:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;34382:85:0;;34401:5;;34382:18;:85::i;34695:621::-;35065:10;;;35064:62;;-1:-1:-1;35081:39:0;;;-1:-1:-1;;;35081:39:0;;35105:4;35081:39;;;;-1:-1:-1;;;;;35081:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;35081:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;35081:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;35081:39:0;:44;35064:62;35056:152;;;;-1:-1:-1;;;35056:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35245:62;;;-1:-1:-1;;;;;35245:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;35245:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;35219:89:0;;35238:5;;35219:18;:89::i;41236:599::-;41401:7;;41441:47;-1:-1:-1;;;;;41441:28:0;;41478:8;41441:47;:28;:47;:::i;:::-;41421:67;-1:-1:-1;41499:18:0;41520:47;-1:-1:-1;;;;;41520:28:0;;41557:8;41520:47;:28;:47;:::i;:::-;41499:68;-1:-1:-1;41580:23:0;41606:17;:8;41619:3;41606:17;:12;:17;:::i;:::-;41580:43;-1:-1:-1;41634:17:0;41654:31;41580:43;41674:10;41654:31;:19;:31;:::i;:::-;41634:51;-1:-1:-1;41696:19:0;41718:40;41742:15;41718:19;:9;41732:4;41718:19;:13;:19;:::i;:::-;:23;:40;:23;:40;:::i;:::-;41696:62;-1:-1:-1;41777:16:0;;41776:51;;41801:26;:9;41815:11;41801:26;:13;:26;:::i;:::-;41776:51;;;41797:1;41776:51;41769:58;41236:599;-1:-1:-1;;;;;;;;;;41236:599:0:o;47598:117::-;47689:12;47688:19;;;47598:117::o;13180:192::-;13266:7;13302:12;13294:6;;;;13286:29;;;;-1:-1:-1;;;13286:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;13286:29:0;-1:-1:-1;;;13338:5:0;;;13180:192::o;36338:1114::-;36942:27;36950:5;-1:-1:-1;;;;;36942:25:0;;:27::i;:::-;36934:71;;;;;-1:-1:-1;;;36934:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;37079:12;37093:23;37128:5;-1:-1:-1;;;;;37120:19:0;37140:4;37120: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;;;37120: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;;37078:67:0;;;;37164:7;37156:52;;;;;-1:-1:-1;;;37156:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37225:17;;:21;37221:224;;37367:10;37356:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37356:30:0;37348:85;;;;-1:-1:-1;;;37348:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31328:619;31388:4;31856:20;;31699:66;31896:23;;;;;;:42;;-1:-1:-1;31923:15:0;;;31896:42;31888:51;31328:619;-1:-1:-1;;;;31328:619:0:o;103436:24146::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;
Swarm Source
bzzr://3ce6424499244d5df6d946ff1e1427463472a95150dd93d28a25f4ce749fd828
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BSC | 100.00% | $3.02 | 1 | $3.02 |
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.