Source Code
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Swap | 24553361 | 11 days ago | 0.00021243 ETH | ||||
| Transfer | 24553361 | 11 days ago | 0.00021243 ETH | ||||
| Transfer | 24177994 | 64 days ago | 0.00051229 ETH | ||||
| Transfer | 24177994 | 64 days ago | 0.00051229 ETH | ||||
| Transfer | 24177588 | 64 days ago | 0.00013492 ETH | ||||
| Transfer | 24177588 | 64 days ago | 0.00013492 ETH | ||||
| Transfer | 24177572 | 64 days ago | 0.00014122 ETH | ||||
| Transfer | 24177572 | 64 days ago | 0.00014122 ETH | ||||
| Transfer | 24177569 | 64 days ago | 0.00008584 ETH | ||||
| Transfer | 24177569 | 64 days ago | 0.00008584 ETH | ||||
| Transfer | 24104406 | 74 days ago | 0.00425441 ETH | ||||
| Transfer | 24104406 | 74 days ago | 0.00425441 ETH | ||||
| Transfer | 24027786 | 85 days ago | 0.00028375 ETH | ||||
| Transfer | 24027786 | 85 days ago | 0.00028375 ETH | ||||
| Transfer | 24027689 | 85 days ago | 0.00000038 ETH | ||||
| Transfer | 24027689 | 85 days ago | 0.00000038 ETH | ||||
| Swap | 24027662 | 85 days ago | 0.01962858 ETH | ||||
| Transfer | 24027662 | 85 days ago | 0.01962858 ETH | ||||
| Swap | 24020251 | 86 days ago | 0.00204744 ETH | ||||
| Swap | 24020251 | 86 days ago | 0.00204744 ETH | ||||
| Deposit | 23797053 | 117 days ago | 0.22569285 ETH | ||||
| Eth To Token Swa... | 23797053 | 117 days ago | 0.02256928 ETH | ||||
| Eth To Token Swa... | 23797053 | 117 days ago | 0.06770785 ETH | ||||
| Swap | 23797053 | 117 days ago | 0.31596999 ETH | ||||
| Deposit | 23726003 | 127 days ago | 0.84189684 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OneSplit
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2020-08-10
*/
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: contracts/IOneSplit.sol
pragma solidity ^0.5.0;
//
// [ msg.sender ]
// | |
// | |
// \_/
// +---------------+ ________________________________
// | OneSplitAudit | _______________________________ \
// +---------------+ \ \
// | | ______________ | | (staticcall)
// | | / ____________ \ | |
// | | (call) / / \ \ | |
// | | / / | | | |
// \_/ | | \_/ \_/
// +--------------+ | | +----------------------+
// | OneSplitWrap | | | | OneSplitViewWrap |
// +--------------+ | | +----------------------+
// | | | | | |
// | | (delegatecall) | | (staticcall) | | (staticcall)
// \_/ | | \_/
// +--------------+ | | +------------------+
// | OneSplit | | | | OneSplitView |
// +--------------+ | | +------------------+
// | | / /
// \ \________________/ /
// \__________________/
//
contract IOneSplitConsts {
// flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ...
uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01;
uint256 internal constant DEPRECATED_FLAG_DISABLE_KYBER = 0x02; // Deprecated
uint256 internal constant FLAG_DISABLE_BANCOR = 0x04;
uint256 internal constant FLAG_DISABLE_OASIS = 0x08;
uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10;
uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20;
uint256 internal constant FLAG_DISABLE_CHAI = 0x40;
uint256 internal constant FLAG_DISABLE_AAVE = 0x80;
uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_BDAI = 0x400;
uint256 internal constant FLAG_DISABLE_IEARN = 0x800;
uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000;
uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000;
uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000;
uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000;
uint256 internal constant FLAG_DISABLE_WETH = 0x80000;
uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_IDLE = 0x800000;
uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000;
uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000;
uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000;
uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000;
uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000;
uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000;
uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000;
uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000;
uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000;
uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000;
uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000;
uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000;
uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_KYBER_ALL = 0x200000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_1 = 0x400000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_2 = 0x800000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_3 = 0x1000000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_4 = 0x2000000000000000;
uint256 internal constant FLAG_ENABLE_CHI_BURN_BY_ORIGIN = 0x4000000000000000;
uint256 internal constant FLAG_DISABLE_MOONISWAP_ALL = 0x8000000000000000;
uint256 internal constant FLAG_DISABLE_MOONISWAP_ETH = 0x10000000000000000;
uint256 internal constant FLAG_DISABLE_MOONISWAP_DAI = 0x20000000000000000;
uint256 internal constant FLAG_DISABLE_MOONISWAP_USDC = 0x40000000000000000;
uint256 internal constant FLAG_DISABLE_MOONISWAP_POOL_TOKEN = 0x80000000000000000;
}
contract IOneSplit is IOneSplitConsts {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
);
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags
)
public
payable
returns(uint256 returnAmount);
}
contract IOneSplitMulti is IOneSplit {
function getExpectedReturnWithGasMulti(
IERC20[] memory tokens,
uint256 amount,
uint256[] memory parts,
uint256[] memory flags,
uint256[] memory destTokenEthPriceTimesGasPrices
)
public
view
returns(
uint256[] memory returnAmounts,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function swapMulti(
IERC20[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256[] memory flags
)
public
payable
returns(uint256 returnAmount);
}
// File: @openzeppelin/contracts/math/SafeMath.sol
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File: contracts/interface/IUniswapExchange.sol
pragma solidity ^0.5.0;
interface IUniswapExchange {
function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought);
function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought);
function ethToTokenSwapInput(uint256 minTokens, uint256 deadline)
external
payable
returns (uint256 tokensBought);
function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline)
external
returns (uint256 ethBought);
function tokenToTokenSwapInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address tokenAddr
) external returns (uint256 tokensBought);
}
// File: contracts/interface/IUniswapFactory.sol
pragma solidity ^0.5.0;
interface IUniswapFactory {
function getExchange(IERC20 token) external view returns (IUniswapExchange exchange);
}
// File: contracts/interface/IKyberNetworkContract.sol
pragma solidity ^0.5.0;
interface IKyberNetworkContract {
function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless)
external
view
returns (address reserve, uint256 rate);
}
// File: contracts/interface/IKyberNetworkProxy.sol
pragma solidity ^0.5.0;
interface IKyberNetworkProxy {
function getExpectedRateAfterFee(
IERC20 src,
IERC20 dest,
uint256 srcQty,
uint256 platformFeeBps,
bytes calldata hint
) external view returns (uint256 expectedRate);
function tradeWithHintAndFee(
IERC20 src,
uint256 srcAmount,
IERC20 dest,
address payable destAddress,
uint256 maxDestAmount,
uint256 minConversionRate,
address payable platformWallet,
uint256 platformFeeBps,
bytes calldata hint
) external payable returns (uint256 destAmount);
function kyberNetworkContract() external view returns (IKyberNetworkContract);
// TODO: Limit usage by tx.gasPrice
// function maxGasPrice() external view returns (uint256);
// TODO: Limit usage by user cap
// function getUserCapInWei(address user) external view returns (uint256);
// function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256);
}
// File: contracts/interface/IKyberStorage.sol
pragma solidity ^0.5.0;
interface IKyberStorage {
function getReserveIdsPerTokenSrc(
IERC20 token
) external view returns (bytes32[] memory);
}
// File: contracts/interface/IKyberHintHandler.sol
pragma solidity ^0.5.0;
interface IKyberHintHandler {
enum TradeType {
BestOfAll,
MaskIn,
MaskOut,
Split
}
function buildTokenToEthHint(
IERC20 tokenSrc,
TradeType tokenToEthType,
bytes32[] calldata tokenToEthReserveIds,
uint256[] calldata tokenToEthSplits
) external view returns (bytes memory hint);
function buildEthToTokenHint(
IERC20 tokenDest,
TradeType ethToTokenType,
bytes32[] calldata ethToTokenReserveIds,
uint256[] calldata ethToTokenSplits
) external view returns (bytes memory hint);
}
// File: contracts/interface/IBancorNetwork.sol
pragma solidity ^0.5.0;
interface IBancorNetwork {
function getReturnByPath(address[] calldata path, uint256 amount)
external
view
returns (uint256 returnAmount, uint256 conversionFee);
function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn)
external
returns (uint256);
function convert(address[] calldata path, uint256 amount, uint256 minReturn)
external
payable
returns (uint256);
}
// File: contracts/interface/IBancorContractRegistry.sol
pragma solidity ^0.5.0;
contract IBancorContractRegistry {
function addressOf(bytes32 contractName) external view returns (address);
}
// File: contracts/interface/IBancorNetworkPathFinder.sol
pragma solidity ^0.5.0;
interface IBancorNetworkPathFinder {
function generatePath(IERC20 sourceToken, IERC20 targetToken)
external
view
returns (address[] memory);
}
// File: contracts/interface/IBancorConverterRegistry.sol
pragma solidity ^0.5.0;
interface IBancorConverterRegistry {
function getConvertibleTokenSmartTokenCount(IERC20 convertibleToken)
external view returns(uint256);
function getConvertibleTokenSmartTokens(IERC20 convertibleToken)
external view returns(address[] memory);
function getConvertibleTokenSmartToken(IERC20 convertibleToken, uint256 index)
external view returns(address);
function isConvertibleTokenSmartToken(IERC20 convertibleToken, address value)
external view returns(bool);
}
// File: contracts/interface/IBancorEtherToken.sol
pragma solidity ^0.5.0;
contract IBancorEtherToken is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
// File: contracts/interface/IBancorFinder.sol
pragma solidity ^0.5.0;
interface IBancorFinder {
function buildBancorPath(
IERC20 fromToken,
IERC20 destToken
)
external
view
returns(address[] memory path);
}
// File: contracts/interface/IOasisExchange.sol
pragma solidity ^0.5.0;
interface IOasisExchange {
function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt)
external
view
returns (uint256 fillAmt);
function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount)
external
returns (uint256 fillAmt);
}
// File: contracts/interface/IWETH.sol
pragma solidity ^0.5.0;
contract IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
// File: contracts/interface/ICurve.sol
pragma solidity ^0.5.0;
interface ICurve {
// solium-disable-next-line mixedcase
function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy);
// solium-disable-next-line mixedcase
function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy);
// solium-disable-next-line mixedcase
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external;
// solium-disable-next-line mixedcase
function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external;
}
contract ICurveRegistry {
function get_pool_info(address pool)
external
view
returns(
uint256[8] memory balances,
uint256[8] memory underlying_balances,
uint256[8] memory decimals,
uint256[8] memory underlying_decimals,
address lp_token,
uint256 A,
uint256 fee
);
}
contract ICurveCalculator {
function get_dy(
int128 nCoins,
uint256[8] calldata balances,
uint256 amp,
uint256 fee,
uint256[8] calldata rates,
uint256[8] calldata precisions,
bool underlying,
int128 i,
int128 j,
uint256[100] calldata dx
) external view returns(uint256[100] memory dy);
}
// File: contracts/interface/IChai.sol
pragma solidity ^0.5.0;
interface IPot {
function dsr() external view returns (uint256);
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}
contract IChai is IERC20 {
function POT() public view returns (IPot);
function join(address dst, uint256 wad) external;
function exit(address src, uint256 wad) external;
}
library ChaiHelper {
IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7);
uint256 private constant RAY = 10**27;
function _mul(uint256 x, uint256 y) private pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) {
// always rounds down
z = _mul(x, y) / RAY;
}
function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) {
// always rounds down
z = _mul(x, RAY) / y;
}
function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) {
// solium-disable-next-line security/no-inline-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
z := base
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := base
}
default {
z := x
}
let half := div(base, 2) // for rounding.
for {
n := div(n, 2)
} n {
n := div(n, 2)
} {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) {
revert(0, 0)
}
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, base)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) {
revert(0, 0)
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, base)
}
}
}
}
}
function potDrip() private view returns (uint256) {
return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi());
}
function chaiPrice(IChai chai) internal view returns(uint256) {
return chaiToDai(chai, 1e18);
}
function daiToChai(
IChai /*chai*/,
uint256 amount
) internal view returns (uint256) {
uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi();
return _rdiv(amount, chi);
}
function chaiToDai(
IChai /*chai*/,
uint256 amount
) internal view returns (uint256) {
uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi();
return _rmul(chi, amount);
}
}
// File: contracts/interface/ICompound.sol
pragma solidity ^0.5.0;
contract ICompound {
function markets(address cToken)
external
view
returns (bool isListed, uint256 collateralFactorMantissa);
}
contract ICompoundToken is IERC20 {
function underlying() external view returns (address);
function exchangeRateStored() external view returns (uint256);
function mint(uint256 mintAmount) external returns (uint256);
function redeem(uint256 redeemTokens) external returns (uint256);
}
contract ICompoundEther is IERC20 {
function mint() external payable;
function redeem(uint256 redeemTokens) external returns (uint256);
}
// File: contracts/interface/ICompoundRegistry.sol
pragma solidity ^0.5.0;
contract ICompoundRegistry {
function tokenByCToken(ICompoundToken cToken) external view returns(IERC20);
function cTokenByToken(IERC20 token) external view returns(ICompoundToken);
}
// File: contracts/interface/IAaveToken.sol
pragma solidity ^0.5.0;
contract IAaveToken is IERC20 {
function underlyingAssetAddress() external view returns (IERC20);
function redeem(uint256 amount) external;
}
interface IAaveLendingPool {
function core() external view returns (address);
function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable;
}
// File: contracts/interface/IAaveRegistry.sol
pragma solidity ^0.5.0;
contract IAaveRegistry {
function tokenByAToken(IAaveToken aToken) external view returns(IERC20);
function aTokenByToken(IERC20 token) external view returns(IAaveToken);
}
// File: contracts/interface/IMooniswap.sol
pragma solidity ^0.5.0;
interface IMooniswapRegistry {
function pools(IERC20 token1, IERC20 token2) external view returns(IMooniswap);
function isPool(address addr) external view returns(bool);
}
interface IMooniswap {
function fee() external view returns (uint256);
function tokens(uint256 i) external view returns (IERC20);
function deposit(uint256[] calldata amounts, uint256[] calldata minAmounts) external payable returns(uint256 fairSupply);
function withdraw(uint256 amount, uint256[] calldata minReturns) external;
function getBalanceForAddition(IERC20 token) external view returns(uint256);
function getBalanceForRemoval(IERC20 token) external view returns(uint256);
function getReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount
)
external
view
returns(uint256 returnAmount);
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
address referral
)
external
payable
returns(uint256 returnAmount);
}
// File: @openzeppelin/contracts/math/Math.sol
pragma solidity ^0.5.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
// File: @openzeppelin/contracts/utils/Address.sol
pragma solidity ^0.5.5;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
pragma solidity ^0.5.0;
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// File: contracts/UniversalERC20.sol
pragma solidity ^0.5.0;
library UniversalERC20 {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000);
IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) {
if (amount == 0) {
return true;
}
if (isETH(token)) {
address(uint160(to)).transfer(amount);
} else {
token.safeTransfer(to, amount);
return true;
}
}
function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()");
if (to != address(this)) {
address(uint160(to)).transfer(amount);
}
if (msg.value > amount) {
msg.sender.transfer(msg.value.sub(amount));
}
} else {
token.safeTransferFrom(from, to, amount);
}
}
function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
if (msg.value > amount) {
// Return remainder if exist
msg.sender.transfer(msg.value.sub(amount));
}
} else {
token.safeTransferFrom(msg.sender, address(this), amount);
}
}
function universalApprove(IERC20 token, address to, uint256 amount) internal {
if (!isETH(token)) {
if (amount == 0) {
token.safeApprove(to, 0);
return;
}
uint256 allowance = token.allowance(address(this), to);
if (allowance < amount) {
if (allowance > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, amount);
}
}
}
function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) {
if (isETH(token)) {
return who.balance;
} else {
return token.balanceOf(who);
}
}
function universalDecimals(IERC20 token) internal view returns (uint256) {
if (isETH(token)) {
return 18;
}
(bool success, bytes memory data) = address(token).staticcall.gas(10000)(
abi.encodeWithSignature("decimals()")
);
if (!success || data.length == 0) {
(success, data) = address(token).staticcall.gas(10000)(
abi.encodeWithSignature("DECIMALS()")
);
}
return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18;
}
function isETH(IERC20 token) internal pure returns(bool) {
return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS));
}
function eq(IERC20 a, IERC20 b) internal pure returns(bool) {
return a == b || (isETH(a) && isETH(b));
}
function notExist(IERC20 token) internal pure returns(bool) {
return (address(token) == address(-1));
}
}
// File: contracts/interface/IUniswapV2Exchange.sol
pragma solidity ^0.5.0;
interface IUniswapV2Exchange {
function getReserves() external view returns(uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
}
library UniswapV2ExchangeLib {
using Math for uint256;
using SafeMath for uint256;
using UniversalERC20 for IERC20;
function getReturn(
IUniswapV2Exchange exchange,
IERC20 fromToken,
IERC20 destToken,
uint amountIn
) internal view returns (uint256 result, bool needSync, bool needSkim) {
uint256 reserveIn = fromToken.universalBalanceOf(address(exchange));
uint256 reserveOut = destToken.universalBalanceOf(address(exchange));
(uint112 reserve0, uint112 reserve1,) = exchange.getReserves();
if (fromToken > destToken) {
(reserve0, reserve1) = (reserve1, reserve0);
}
needSync = (reserveIn < reserve0 || reserveOut < reserve1);
needSkim = !needSync && (reserveIn > reserve0 || reserveOut > reserve1);
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(Math.min(reserveOut, reserve1));
uint256 denominator = Math.min(reserveIn, reserve0).mul(1000).add(amountInWithFee);
result = (denominator == 0) ? 0 : numerator.div(denominator);
}
}
// File: contracts/interface/IUniswapV2Factory.sol
pragma solidity ^0.5.0;
interface IUniswapV2Factory {
function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair);
}
// File: contracts/interface/IDForceSwap.sol
pragma solidity ^0.5.0;
interface IDForceSwap {
function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256);
function swap(IERC20 input, IERC20 output, uint256 amount) external;
}
// File: contracts/interface/IShell.sol
pragma solidity ^0.5.0;
interface IShell {
function viewOriginTrade(
address origin,
address target,
uint256 originAmount
) external view returns (uint256);
function swapByOrigin(
address origin,
address target,
uint256 originAmount,
uint256 minTargetAmount,
uint256 deadline
) external returns (uint256);
}
// File: contracts/interface/IMStable.sol
pragma solidity ^0.5.0;
contract IMStable is IERC20 {
function getSwapOutput(
IERC20 _input,
IERC20 _output,
uint256 _quantity
)
external
view
returns (bool, string memory, uint256 output);
function swap(
IERC20 _input,
IERC20 _output,
uint256 _quantity,
address _recipient
)
external
returns (uint256 output);
function redeem(
IERC20 _basset,
uint256 _bassetQuantity
)
external
returns (uint256 massetRedeemed);
}
interface IMassetValidationHelper {
/**
* @dev Returns a valid bAsset to redeem
* @param _mAsset Masset addr
* @return valid bool
* @return string message
* @return address of bAsset to redeem
*/
function suggestRedeemAsset(
IERC20 _mAsset
)
external
view
returns (
bool valid,
string memory err,
address token
);
/**
* @dev Returns a valid bAsset with which to mint
* @param _mAsset Masset addr
* @return valid bool
* @return string message
* @return address of bAsset to mint
*/
function suggestMintAsset(
IERC20 _mAsset
)
external
view
returns (
bool valid,
string memory err,
address token
);
/**
* @dev Determines if a given Redemption is valid
* @param _mAsset Address of the given mAsset (e.g. mUSD)
* @param _mAssetQuantity Amount of mAsset to redeem (in mUSD units)
* @param _outputBasset Desired output bAsset
* @return valid
* @return validity reason
* @return output in bAsset units
* @return bAssetQuantityArg - required input argument to the 'redeem' call
*/
function getRedeemValidity(
IERC20 _mAsset,
uint256 _mAssetQuantity,
IERC20 _outputBasset
)
external
view
returns (
bool valid,
string memory,
uint256 output,
uint256 bassetQuantityArg
);
}
// File: contracts/interface/IBalancerPool.sol
pragma solidity ^0.5.0;
interface IBalancerPool {
function getSwapFee()
external view returns (uint256 balance);
function getDenormalizedWeight(IERC20 token)
external view returns (uint256 balance);
function getBalance(IERC20 token)
external view returns (uint256 balance);
function swapExactAmountIn(
IERC20 tokenIn,
uint256 tokenAmountIn,
IERC20 tokenOut,
uint256 minAmountOut,
uint256 maxPrice
)
external
returns (uint256 tokenAmountOut, uint256 spotPriceAfter);
}
// 0xA961672E8Db773be387e775bc4937C678F3ddF9a
interface IBalancerHelper {
function getReturns(
IBalancerPool pool,
IERC20 fromToken,
IERC20 destToken,
uint256[] calldata amounts
)
external
view
returns(uint256[] memory rets);
}
// File: contracts/interface/IBalancerRegistry.sol
pragma solidity ^0.5.0;
interface IBalancerRegistry {
event PoolAdded(
address indexed pool
);
event PoolTokenPairAdded(
address indexed pool,
address indexed fromToken,
address indexed destToken
);
event IndicesUpdated(
address indexed fromToken,
address indexed destToken,
bytes32 oldIndices,
bytes32 newIndices
);
// Get info about pool pair for 1 SLOAD
function getPairInfo(address pool, address fromToken, address destToken)
external view returns(uint256 weight1, uint256 weight2, uint256 swapFee);
// Pools
function checkAddedPools(address pool)
external view returns(bool);
function getAddedPoolsLength()
external view returns(uint256);
function getAddedPools()
external view returns(address[] memory);
function getAddedPoolsWithLimit(uint256 offset, uint256 limit)
external view returns(address[] memory result);
// Tokens
function getAllTokensLength()
external view returns(uint256);
function getAllTokens()
external view returns(address[] memory);
function getAllTokensWithLimit(uint256 offset, uint256 limit)
external view returns(address[] memory result);
// Pairs
function getPoolsLength(address fromToken, address destToken)
external view returns(uint256);
function getPools(address fromToken, address destToken)
external view returns(address[] memory);
function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit)
external view returns(address[] memory result);
function getBestPools(address fromToken, address destToken)
external view returns(address[] memory pools);
function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit)
external view returns(address[] memory pools);
// Get swap rates
function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount)
external view returns(uint256);
function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts)
external view returns(uint256[] memory result);
// Add and update registry
function addPool(address pool) external returns(uint256 listed);
function addPools(address[] calldata pools) external returns(uint256[] memory listed);
function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external;
}
// File: contracts/BalancerLib.sol
pragma solidity ^0.5.0;
library BalancerLib {
uint public constant BONE = 10**18;
uint public constant MIN_BOUND_TOKENS = 2;
uint public constant MAX_BOUND_TOKENS = 8;
uint public constant MIN_FEE = BONE / 10**6;
uint public constant MAX_FEE = BONE / 10;
uint public constant EXIT_FEE = 0;
uint public constant MIN_WEIGHT = BONE;
uint public constant MAX_WEIGHT = BONE * 50;
uint public constant MAX_TOTAL_WEIGHT = BONE * 50;
uint public constant MIN_BALANCE = BONE / 10**12;
uint public constant INIT_POOL_SUPPLY = BONE * 100;
uint public constant MIN_BPOW_BASE = 1 wei;
uint public constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;
uint public constant BPOW_PRECISION = BONE / 10**10;
uint public constant MAX_IN_RATIO = BONE / 2;
uint public constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;
function btoi(uint a)
internal pure
returns (uint)
{
return a / BONE;
}
function bfloor(uint a)
internal pure
returns (uint)
{
return btoi(a) * BONE;
}
function badd(uint a, uint b)
internal pure
returns (uint)
{
uint c = a + b;
require(c >= a, "ERR_ADD_OVERFLOW");
return c;
}
function bsub(uint a, uint b)
internal pure
returns (uint)
{
(uint c, bool flag) = bsubSign(a, b);
require(!flag, "ERR_SUB_UNDERFLOW");
return c;
}
function bsubSign(uint a, uint b)
internal pure
returns (uint, bool)
{
if (a >= b) {
return (a - b, false);
} else {
return (b - a, true);
}
}
function bmul(uint a, uint b)
internal pure
returns (uint)
{
uint c0 = a * b;
require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
uint c1 = c0 + (BONE / 2);
require(c1 >= c0, "ERR_MUL_OVERFLOW");
uint c2 = c1 / BONE;
return c2;
}
function bdiv(uint a, uint b)
internal pure
returns (uint)
{
require(b != 0, "ERR_DIV_ZERO");
uint c0 = a * BONE;
require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow
uint c1 = c0 + (b / 2);
require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require
uint c2 = c1 / b;
return c2;
}
// DSMath.wpow
function bpowi(uint a, uint n)
internal pure
returns (uint)
{
uint z = n % 2 != 0 ? a : BONE;
for (n /= 2; n != 0; n /= 2) {
a = bmul(a, a);
if (n % 2 != 0) {
z = bmul(z, a);
}
}
return z;
}
// Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
// Use `bpowi` for `b^e` and `bpowK` for k iterations
// of approximation of b^0.w
function bpow(uint base, uint exp)
internal pure
returns (uint)
{
require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW");
require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH");
uint whole = bfloor(exp);
uint remain = bsub(exp, whole);
uint wholePow = bpowi(base, btoi(whole));
if (remain == 0) {
return wholePow;
}
uint partialResult = bpowApprox(base, remain, BPOW_PRECISION);
return bmul(wholePow, partialResult);
}
function bpowApprox(uint base, uint exp, uint precision)
internal pure
returns (uint)
{
// term 0:
uint a = exp;
(uint x, bool xneg) = bsubSign(base, BONE);
uint term = BONE;
uint sum = term;
bool negative = false;
// term(k) = numer / denom
// = (product(a - i - 1, i=1-->k) * x^k) / (k!)
// each iteration, multiply previous term by (a-(k-1)) * x / k
// continue until term is less than precision
for (uint i = 1; term >= precision; i++) {
uint bigK = i * BONE;
(uint c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
term = bmul(term, bmul(c, x));
term = bdiv(term, bigK);
if (term == 0) break;
if (xneg) negative = !negative;
if (cneg) negative = !negative;
if (negative) {
sum = bsub(sum, term);
} else {
sum = badd(sum, term);
}
}
return sum;
}
/**********************************************************************************************
// calcSpotPrice //
// sP = spotPrice //
// bI = tokenBalanceIn ( bI / wI ) 1 //
// bO = tokenBalanceOut sP = ----------- * ---------- //
// wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) //
// wO = tokenWeightOut //
// sF = swapFee //
**********************************************************************************************/
function calcSpotPrice(
uint tokenBalanceIn,
uint tokenWeightIn,
uint tokenBalanceOut,
uint tokenWeightOut,
uint swapFee
)
internal pure
returns (uint spotPrice)
{
uint numer = bdiv(tokenBalanceIn, tokenWeightIn);
uint denom = bdiv(tokenBalanceOut, tokenWeightOut);
uint ratio = bdiv(numer, denom);
uint scale = bdiv(BONE, bsub(BONE, swapFee));
return (spotPrice = bmul(ratio, scale));
}
/**********************************************************************************************
// calcOutGivenIn //
// aO = tokenAmountOut //
// bO = tokenBalanceOut //
// bI = tokenBalanceIn / / bI \ (wI / wO) \ //
// aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | //
// wI = tokenWeightIn \ \ ( bI + ( aI * ( 1 - sF )) / / //
// wO = tokenWeightOut //
// sF = swapFee //
**********************************************************************************************/
function calcOutGivenIn(
uint tokenBalanceIn,
uint tokenWeightIn,
uint tokenBalanceOut,
uint tokenWeightOut,
uint tokenAmountIn,
uint swapFee
)
internal pure
returns (uint tokenAmountOut)
{
uint weightRatio = bdiv(tokenWeightIn, tokenWeightOut);
uint adjustedIn = bsub(BONE, swapFee);
adjustedIn = bmul(tokenAmountIn, adjustedIn);
uint y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));
if (y == 0) {
return 0;
}
uint foo = bpow(y, weightRatio);
uint bar = bsub(BONE, foo);
tokenAmountOut = bmul(tokenBalanceOut, bar);
return tokenAmountOut;
}
/**********************************************************************************************
// calcInGivenOut //
// aI = tokenAmountIn //
// bO = tokenBalanceOut / / bO \ (wO / wI) \ //
// bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | //
// aO = tokenAmountOut aI = \ \ ( bO - aO ) / / //
// wI = tokenWeightIn -------------------------------------------- //
// wO = tokenWeightOut ( 1 - sF ) //
// sF = swapFee //
**********************************************************************************************/
function calcInGivenOut(
uint tokenBalanceIn,
uint tokenWeightIn,
uint tokenBalanceOut,
uint tokenWeightOut,
uint tokenAmountOut,
uint swapFee
)
internal pure
returns (uint tokenAmountIn)
{
uint weightRatio = bdiv(tokenWeightOut, tokenWeightIn);
uint diff = bsub(tokenBalanceOut, tokenAmountOut);
uint y = bdiv(tokenBalanceOut, diff);
if (y == 0) {
return 0;
}
uint foo = bpow(y, weightRatio);
foo = bsub(foo, BONE);
tokenAmountIn = bsub(BONE, swapFee);
tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);
return tokenAmountIn;
}
/**********************************************************************************************
// calcPoolOutGivenSingleIn //
// pAo = poolAmountOut / \ //
// tAi = tokenAmountIn /// / // wI \ \\ \ wI \ //
// wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \ -- \ //
// tW = totalWeight pAo=|| \ \ \\ tW / // | ^ tW | * pS - pS //
// tBi = tokenBalanceIn \\ ------------------------------------- / / //
// pS = poolSupply \\ tBi / / //
// sF = swapFee \ / //
**********************************************************************************************/
function calcPoolOutGivenSingleIn(
uint tokenBalanceIn,
uint tokenWeightIn,
uint poolSupply,
uint totalWeight,
uint tokenAmountIn,
uint swapFee
)
internal pure
returns (uint poolAmountOut)
{
// Charge the trading fee for the proportion of tokenAi
/// which is implicitly traded to the other pool tokens.
// That proportion is (1- weightTokenIn)
// tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);
uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);
uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
uint tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));
uint newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);
uint tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);
// uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;
uint poolRatio = bpow(tokenInRatio, normalizedWeight);
uint newPoolSupply = bmul(poolRatio, poolSupply);
poolAmountOut = bsub(newPoolSupply, poolSupply);
return poolAmountOut;
}
/**********************************************************************************************
// calcSingleInGivenPoolOut //
// tAi = tokenAmountIn //(pS + pAo)\ / 1 \\ //
// pS = poolSupply || --------- | ^ | --------- || * bI - bI //
// pAo = poolAmountOut \\ pS / \(wI / tW)// //
// bI = balanceIn tAi = -------------------------------------------- //
// wI = weightIn / wI \ //
// tW = totalWeight | 1 - ---- | * sF //
// sF = swapFee \ tW / //
**********************************************************************************************/
function calcSingleInGivenPoolOut(
uint tokenBalanceIn,
uint tokenWeightIn,
uint poolSupply,
uint totalWeight,
uint poolAmountOut,
uint swapFee
)
internal pure
returns (uint tokenAmountIn)
{
uint normalizedWeight = bdiv(tokenWeightIn, totalWeight);
uint newPoolSupply = badd(poolSupply, poolAmountOut);
uint poolRatio = bdiv(newPoolSupply, poolSupply);
//uint newBalTi = poolRatio^(1/weightTi) * balTi;
uint boo = bdiv(BONE, normalizedWeight);
uint tokenInRatio = bpow(poolRatio, boo);
uint newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);
uint tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);
// Do reverse order of fees charged in joinswap_ExternAmountIn, this way
// ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```
//uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;
uint zar = bmul(bsub(BONE, normalizedWeight), swapFee);
tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));
return tokenAmountIn;
}
/**********************************************************************************************
// calcSingleOutGivenPoolIn //
// tAo = tokenAmountOut / / \\ //
// bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \ / 1 \ \\ //
// pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || //
// ps = poolSupply \ \\ pS / \(wO / tW)/ // //
// wI = tokenWeightIn tAo = \ \ // //
// tW = totalWeight / / wO \ \ //
// sF = swapFee * | 1 - | 1 - ---- | * sF | //
// eF = exitFee \ \ tW / / //
**********************************************************************************************/
function calcSingleOutGivenPoolIn(
uint tokenBalanceOut,
uint tokenWeightOut,
uint poolSupply,
uint totalWeight,
uint poolAmountIn,
uint swapFee
)
internal pure
returns (uint tokenAmountOut)
{
uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
// charge exit fee on the pool token side
// pAiAfterExitFee = pAi*(1-exitFee)
uint poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE));
uint newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);
uint poolRatio = bdiv(newPoolSupply, poolSupply);
// newBalTo = poolRatio^(1/weightTo) * balTo;
uint tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));
uint newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);
uint tokenAmountOutBeforeSwapFee = bsub(tokenBalanceOut, newTokenBalanceOut);
// charge swap fee on the output token side
//uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)
uint zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));
return tokenAmountOut;
}
/**********************************************************************************************
// calcPoolInGivenSingleOut //
// pAi = poolAmountIn // / tAo \\ / wO \ \ //
// bO = tokenBalanceOut // | bO - -------------------------- |\ | ---- | \ //
// tAo = tokenAmountOut pS - || \ 1 - ((1 - (tO / tW)) * sF)/ | ^ \ tW / * pS | //
// ps = poolSupply \\ -----------------------------------/ / //
// wO = tokenWeightOut pAi = \\ bO / / //
// tW = totalWeight ------------------------------------------------------------- //
// sF = swapFee ( 1 - eF ) //
// eF = exitFee //
**********************************************************************************************/
function calcPoolInGivenSingleOut(
uint tokenBalanceOut,
uint tokenWeightOut,
uint poolSupply,
uint totalWeight,
uint tokenAmountOut,
uint swapFee
)
internal pure
returns (uint poolAmountIn)
{
// charge swap fee on the output token side
uint normalizedWeight = bdiv(tokenWeightOut, totalWeight);
//uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;
uint zoo = bsub(BONE, normalizedWeight);
uint zar = bmul(zoo, swapFee);
uint tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));
uint newTokenBalanceOut = bsub(tokenBalanceOut, tokenAmountOutBeforeSwapFee);
uint tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);
//uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;
uint poolRatio = bpow(tokenOutRatio, normalizedWeight);
uint newPoolSupply = bmul(poolRatio, poolSupply);
uint poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);
// charge exit fee on the pool token side
// pAi = pAiAfterExitFee/(1-exitFee)
poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE));
return poolAmountIn;
}
}
// File: contracts/OneSplitBase.sol
pragma solidity ^0.5.0;
contract IOneSplitView is IOneSplitConsts {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
);
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
}
library DisableFlags {
function check(uint256 flags, uint256 flag) internal pure returns(bool) {
return (flags & flag) != 0;
}
}
contract OneSplitRoot is IOneSplitView {
using SafeMath for uint256;
using DisableFlags for uint256;
using UniversalERC20 for IERC20;
using UniversalERC20 for IWETH;
using UniswapV2ExchangeLib for IUniswapV2Exchange;
using ChaiHelper for IChai;
uint256 constant internal DEXES_COUNT = 34;
IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
IERC20 constant internal ZERO_ADDRESS = IERC20(0);
IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315);
IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215);
IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376);
IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53);
IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51);
IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1);
IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D);
IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847);
IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380);
IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6);
IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e);
IKyberStorage constant internal kyberStorage = IKyberStorage(0xC8fb12402cB16970F3C5F4b48Ff68Eb9D1289301);
IKyberHintHandler constant internal kyberHintHandler = IKyberHintHandler(0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C);
IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95);
IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4);
IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861);
//IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518);
IBancorFinder constant internal bancorFinder = IBancorFinder(0x2B344e14dc2641D11D338C053C908c7A7D4c30B9);
IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D);
ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56);
ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C);
ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51);
ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27);
ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD);
ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763);
ICurve constant internal curveRenBTC = ICurve(0x93054188d876f558f4a66B2EF1d97d16eDf0895B);
ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E);
ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714);
IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D);
IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);
ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5);
IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0x71CD6666064C3A1354a3B4dca5fA1E2D3ee7D303);
IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2);
IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5);
IMassetValidationHelper constant internal musd_helper = IMassetValidationHelper(0xaBcC93c3be238884cc3309C19Afd128fAfC16911);
IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982);
ICurveCalculator constant internal curveCalculator = ICurveCalculator(0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E);
ICurveRegistry constant internal curveRegistry = ICurveRegistry(0x7002B727Ef8F5571Cb5F9D70D13DBEEb4dFAe9d1);
ICompoundRegistry constant internal compoundRegistry = ICompoundRegistry(0xF451Dbd7Ba14BFa7B1B78A766D3Ed438F79EE1D1);
IAaveRegistry constant internal aaveRegistry = IAaveRegistry(0xEd8b133B7B88366E01Bb9E38305Ab11c26521494);
IBalancerHelper constant internal balancerHelper = IBalancerHelper(0xA961672E8Db773be387e775bc4937C678F3ddF9a);
int256 internal constant VERY_NEGATIVE_VALUE = -1e72;
function _findBestDistribution(
uint256 s, // parts
int256[][] memory amounts // exchangesReturns
)
internal
pure
returns(
int256 returnAmount,
uint256[] memory distribution
)
{
uint256 n = amounts.length;
int256[][] memory answer = new int256[][](n); // int[n][s+1]
uint256[][] memory parent = new uint256[][](n); // int[n][s+1]
for (uint i = 0; i < n; i++) {
answer[i] = new int256[](s + 1);
parent[i] = new uint256[](s + 1);
}
for (uint j = 0; j <= s; j++) {
answer[0][j] = amounts[0][j];
for (uint i = 1; i < n; i++) {
answer[i][j] = -1e72;
}
parent[0][j] = 0;
}
for (uint i = 1; i < n; i++) {
for (uint j = 0; j <= s; j++) {
answer[i][j] = answer[i - 1][j];
parent[i][j] = j;
for (uint k = 1; k <= j; k++) {
if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) {
answer[i][j] = answer[i - 1][j - k] + amounts[i][k];
parent[i][j] = j - k;
}
}
}
}
distribution = new uint256[](DEXES_COUNT);
uint256 partsLeft = s;
for (uint curExchange = n - 1; partsLeft > 0; curExchange--) {
distribution[curExchange] = partsLeft - parent[curExchange][partsLeft];
partsLeft = parent[curExchange][partsLeft];
}
returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s];
}
function _kyberReserveIdByTokens(
IERC20 fromToken,
IERC20 destToken
) internal view returns(bytes32) {
if (!fromToken.isETH() && !destToken.isETH()) {
return 0;
}
bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc(
fromToken.isETH() ? destToken : fromToken
);
for (uint i = 0; i < reserveIds.length; i++) {
if ((uint256(reserveIds[i]) >> 248) != 0xBB && // Bridge
reserveIds[i] != 0xff4b796265722046707200000000000000000000000000000000000000000000 && // Reserve 1
reserveIds[i] != 0xffabcd0000000000000000000000000000000000000000000000000000000000 && // Reserve 2
reserveIds[i] != 0xff4f6e65426974205175616e7400000000000000000000000000000000000000) // Reserve 3
{
return reserveIds[i];
}
}
return 0;
}
function _scaleDestTokenEthPriceTimesGasPrice(
IERC20 fromToken,
IERC20 destToken,
uint256 destTokenEthPriceTimesGasPrice
) internal view returns(uint256) {
if (fromToken == destToken) {
return destTokenEthPriceTimesGasPrice;
}
uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 0.01 ether);
uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 0.01 ether);
if (div > 0) {
return destTokenEthPriceTimesGasPrice.mul(mul).div(div);
}
return 0;
}
function _cheapGetPrice(
IERC20 fromToken,
IERC20 destToken,
uint256 amount
) internal view returns(uint256 returnAmount) {
(returnAmount,,) = this.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
1,
FLAG_DISABLE_SPLIT_RECALCULATION |
FLAG_DISABLE_ALL_SPLIT_SOURCES |
FLAG_DISABLE_UNISWAP_V2_ALL |
FLAG_DISABLE_UNISWAP,
0
);
}
function _linearInterpolation(
uint256 value,
uint256 parts
) internal pure returns(uint256[] memory rets) {
rets = new uint256[](parts);
for (uint i = 0; i < parts; i++) {
rets[i] = value.mul(i + 1).div(parts);
}
}
function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) {
return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB);
}
}
contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = this.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _getExpectedReturnRespectingGasFloor(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _getExpectedReturnRespectingGasFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
}
contract OneSplitView is IOneSplitView, OneSplitRoot {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
distribution = new uint256[](DEXES_COUNT);
if (fromToken == destToken) {
return (amount, 0, distribution);
}
function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags);
int256[][] memory matrix = new int256[][](DEXES_COUNT);
uint256[DEXES_COUNT] memory gases;
bool atLeastOnePositive = false;
for (uint i = 0; i < DEXES_COUNT; i++) {
uint256[] memory rets;
(rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags);
// Prepend zero and sub gas
int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18));
matrix[i] = new int256[](parts + 1);
for (uint j = 0; j < rets.length; j++) {
matrix[i][j + 1] = int256(rets[j]) - gas;
atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0);
}
}
if (!atLeastOnePositive) {
for (uint i = 0; i < DEXES_COUNT; i++) {
for (uint j = 1; j < parts + 1; j++) {
if (matrix[i][j] == 0) {
matrix[i][j] = VERY_NEGATIVE_VALUE;
}
}
}
}
(, distribution) = _findBestDistribution(parts, matrix);
(returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution(
Args({
fromToken: fromToken,
destToken: destToken,
amount: amount,
parts: parts,
flags: flags,
destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice,
distribution: distribution,
matrix: matrix,
gases: gases,
reserves: reserves
})
);
return (returnAmount, estimateGasAmount, distribution);
}
struct Args {
IERC20 fromToken;
IERC20 destToken;
uint256 amount;
uint256 parts;
uint256 flags;
uint256 destTokenEthPriceTimesGasPrice;
uint256[] distribution;
int256[][] matrix;
uint256[DEXES_COUNT] gases;
function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] reserves;
}
function _getReturnAndGasByDistribution(
Args memory args
) internal view returns(uint256 returnAmount, uint256 estimateGasAmount) {
bool[DEXES_COUNT] memory exact = [
true, // "Uniswap",
false, // "Kyber",
false, // "Bancor",
false, // "Oasis",
true, // "Curve Compound",
true, // "Curve USDT",
true, // "Curve Y",
true, // "Curve Binance",
true, // "Curve Synthetix",
true, // "Uniswap Compound",
true, // "Uniswap CHAI",
true, // "Uniswap Aave",
true, // "Mooniswap 1",
true, // "Uniswap V2",
true, // "Uniswap V2 (ETH)",
true, // "Uniswap V2 (DAI)",
true, // "Uniswap V2 (USDC)",
true, // "Curve Pax",
true, // "Curve RenBTC",
true, // "Curve tBTC",
true, // "Dforce XSwap",
false, // "Shell",
true, // "mStable",
true, // "Curve sBTC"
true, // "Balancer 1"
true, // "Balancer 2"
true, // "Balancer 3"
true, // "Kyber 1"
true, // "Kyber 2"
true, // "Kyber 3"
true, // "Kyber 4"
true, // "Mooniswap 2"
true, // "Mooniswap 3"
true // "Mooniswap 4"
];
for (uint i = 0; i < DEXES_COUNT; i++) {
if (args.distribution[i] > 0) {
if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) {
estimateGasAmount = estimateGasAmount.add(args.gases[i]);
int256 value = args.matrix[i][args.distribution[i]];
returnAmount = returnAmount.add(uint256(
(value == VERY_NEGATIVE_VALUE ? 0 : value) +
int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18))
));
}
else {
(uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags);
estimateGasAmount = estimateGasAmount.add(gas);
returnAmount = returnAmount.add(rets[0]);
}
}
}
}
function _getAllReserves(uint256 flags)
internal
pure
returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory)
{
bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES);
return [
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap,
_calculateNoReturn, // invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber,
invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor,
invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave,
invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC,
invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap,
invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell,
invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_1) ? _calculateNoReturn : calculateKyber1,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_2) ? _calculateNoReturn : calculateKyber2,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_3) ? _calculateNoReturn : calculateKyber3,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_4) ? _calculateNoReturn : calculateKyber4,
invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_ETH) ? _calculateNoReturn : calculateMooniswapOverETH,
invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_DAI) ? _calculateNoReturn : calculateMooniswapOverDAI,
invert != flags.check(FLAG_DISABLE_MOONISWAP_ALL | FLAG_DISABLE_MOONISWAP_USDC) ? _calculateNoReturn : calculateMooniswapOverUSDC
];
}
function _calculateNoGas(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 /*parts*/,
uint256 /*destTokenEthPriceTimesGasPrice*/,
uint256 /*flags*/,
uint256 /*destTokenEthPrice*/
) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) {
this;
}
// View Helpers
struct Balances {
uint256 src;
uint256 dst;
}
function _calculateBalancer(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 poolIndex
) internal view returns(uint256[] memory rets, uint256 gas) {
address[] memory pools = balancerRegistry.getBestPoolsWithLimit(
address(fromToken.isETH() ? weth : fromToken),
address(destToken.isETH() ? weth : destToken),
poolIndex + 1
);
if (poolIndex >= pools.length) {
return (new uint256[](parts), 0);
}
rets = balancerHelper.getReturns(
IBalancerPool(pools[poolIndex]),
fromToken.isETH() ? weth : fromToken,
destToken.isETH() ? weth : destToken,
_linearInterpolation(amount, parts)
);
gas = 75_000 + (fromToken.isETH() || destToken.isETH() ? 0 : 65_000);
}
function calculateBalancer1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
0
);
}
function calculateBalancer2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
1
);
}
function calculateBalancer3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
2
);
}
function calculateMStableMUSD(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](parts);
if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) ||
(destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd))
{
return (rets, 0);
}
for (uint i = 1; i <= parts; i *= 2) {
(bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector(
musd.getSwapOutput.selector,
fromToken,
destToken,
amount.mul(parts.div(i)).div(parts)
));
if (success && data.length > 0) {
(,, uint256 maxRet) = abi.decode(data, (bool,string,uint256));
if (maxRet > 0) {
for (uint j = 0; j < parts.div(i); j++) {
rets[j] = maxRet.mul(j + 1).div(parts.div(i));
}
break;
}
}
}
return (
rets,
700_000
);
}
function _getCurvePoolInfo(
ICurve curve,
bool haveUnderlying
) internal view returns(
uint256[8] memory balances,
uint256[8] memory precisions,
uint256[8] memory rates,
uint256 amp,
uint256 fee
) {
uint256[8] memory underlying_balances;
uint256[8] memory decimals;
uint256[8] memory underlying_decimals;
(
balances,
underlying_balances,
decimals,
underlying_decimals,
/*address lp_token*/,
amp,
fee
) = curveRegistry.get_pool_info(address(curve));
for (uint k = 0; k < 8 && balances[k] > 0; k++) {
precisions[k] = 10 ** (18 - (haveUnderlying ? underlying_decimals : decimals)[k]);
if (haveUnderlying) {
rates[k] = underlying_balances[k].mul(1e18).div(balances[k]);
} else {
rates[k] = 1e18;
}
}
}
function _calculateCurveSelector(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
ICurve curve,
bool haveUnderlying,
IERC20[] memory tokens
) internal view returns(uint256[] memory rets) {
rets = new uint256[](parts);
int128 i = 0;
int128 j = 0;
for (uint t = 0; t < tokens.length; t++) {
if (fromToken == tokens[t]) {
i = int128(t + 1);
}
if (destToken == tokens[t]) {
j = int128(t + 1);
}
}
if (i == 0 || j == 0) {
return rets;
}
bytes memory data = abi.encodePacked(
uint256(haveUnderlying ? 1 : 0),
uint256(i - 1),
uint256(j - 1),
_linearInterpolation100(amount, parts)
);
(
uint256[8] memory balances,
uint256[8] memory precisions,
uint256[8] memory rates,
uint256 amp,
uint256 fee
) = _getCurvePoolInfo(curve, haveUnderlying);
bool success;
(success, data) = address(curveCalculator).staticcall(
abi.encodePacked(
abi.encodeWithSelector(
curveCalculator.get_dy.selector,
tokens.length,
balances,
amp,
fee,
rates,
precisions
),
data
)
);
if (!success || data.length == 0) {
return rets;
}
uint256[100] memory dy = abi.decode(data, (uint256[100]));
for (uint t = 0; t < parts; t++) {
rets[t] = dy[t];
}
}
function _linearInterpolation100(
uint256 value,
uint256 parts
) internal pure returns(uint256[100] memory rets) {
for (uint i = 0; i < parts; i++) {
rets[i] = value.mul(i + 1).div(parts);
}
}
function calculateCurveCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](2);
tokens[0] = dai;
tokens[1] = usdc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveCompound,
true,
tokens
), 720_000);
}
function calculateCurveUSDT(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveUSDT,
true,
tokens
), 720_000);
}
function calculateCurveY(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = tusd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveY,
true,
tokens
), 1_400_000);
}
function calculateCurveBinance(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = busd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveBinance,
true,
tokens
), 1_400_000);
}
function calculateCurveSynthetix(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = susd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveSynthetix,
true,
tokens
), 200_000);
}
function calculateCurvePAX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = pax;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curvePAX,
true,
tokens
), 1_000_000);
}
function calculateCurveRenBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](2);
tokens[0] = renbtc;
tokens[1] = wbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveRenBTC,
false,
tokens
), 130_000);
}
function calculateCurveTBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = tbtc;
tokens[1] = wbtc;
tokens[2] = hbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveTBTC,
false,
tokens
), 145_000);
}
function calculateCurveSBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = renbtc;
tokens[1] = wbtc;
tokens[2] = sbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveSBTC,
false,
tokens
), 150_000);
}
function calculateShell(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
(bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector(
shell.viewOriginTrade.selector,
fromToken,
destToken,
amount
));
if (!success || data.length == 0) {
return (new uint256[](parts), 0);
}
uint256 maxRet = abi.decode(data, (uint256));
return (_linearInterpolation(maxRet, parts), 300_000);
}
function calculateDforceSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
(bool success, bytes memory data) = address(dforceSwap).staticcall(
abi.encodeWithSelector(
dforceSwap.getAmountByInput.selector,
fromToken,
destToken,
amount
)
);
if (!success || data.length == 0) {
return (new uint256[](parts), 0);
}
uint256 maxRet = abi.decode(data, (uint256));
uint256 available = destToken.universalBalanceOf(address(dforceSwap));
if (maxRet > available) {
return (new uint256[](parts), 0);
}
return (_linearInterpolation(maxRet, parts), 160_000);
}
function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) {
if (amount == 0) {
return 0;
}
return amount.mul(toBalance).mul(997).div(
fromBalance.mul(1000).add(amount.mul(997))
);
}
function _calculateUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256[] memory amounts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = amounts;
if (!fromToken.isETH()) {
IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken);
if (fromExchange == IUniswapExchange(0)) {
return (new uint256[](rets.length), 0);
}
uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange));
uint256 fromEtherBalance = address(fromExchange).balance;
for (uint i = 0; i < rets.length; i++) {
rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]);
}
}
if (!destToken.isETH()) {
IUniswapExchange toExchange = uniswapFactory.getExchange(destToken);
if (toExchange == IUniswapExchange(0)) {
return (new uint256[](rets.length), 0);
}
uint256 toEtherBalance = address(toExchange).balance;
uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange));
for (uint i = 0; i < rets.length; i++) {
rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]);
}
}
return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000);
}
function calculateUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateUniswap(
fromToken,
destToken,
_linearInterpolation(amount, parts),
flags
);
}
function _calculateUniswapWrapped(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 midTokenPrice,
uint256 flags,
uint256 gas1,
uint256 gas2
) internal view returns(uint256[] memory rets, uint256 gas) {
if (!fromToken.isETH() && destToken.isETH()) {
(rets, gas) = _calculateUniswap(
midToken,
destToken,
_linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts),
flags
);
return (rets, gas + gas1);
}
else if (fromToken.isETH() && !destToken.isETH()) {
(rets, gas) = _calculateUniswap(
fromToken,
midToken,
_linearInterpolation(amount, parts),
flags
);
for (uint i = 0; i < parts; i++) {
rets[i] = rets[i].mul(midTokenPrice).div(1e18);
}
return (rets, gas + gas2);
}
return (new uint256[](parts), 0);
}
function calculateUniswapCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20 midPreToken;
if (!fromToken.isETH() && destToken.isETH()) {
midPreToken = fromToken;
}
else if (!destToken.isETH() && fromToken.isETH()) {
midPreToken = destToken;
}
if (!midPreToken.isETH()) {
ICompoundToken midToken = compoundRegistry.cTokenByToken(midPreToken);
if (midToken != ICompoundToken(0)) {
return _calculateUniswapWrapped(
fromToken,
midToken,
destToken,
amount,
parts,
midToken.exchangeRateStored(),
flags,
200_000,
200_000
);
}
}
return (new uint256[](parts), 0);
}
function calculateUniswapChai(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == dai && destToken.isETH() ||
fromToken.isETH() && destToken == dai)
{
return _calculateUniswapWrapped(
fromToken,
chai,
destToken,
amount,
parts,
chai.chaiPrice(),
flags,
180_000,
160_000
);
}
return (new uint256[](parts), 0);
}
function calculateUniswapAave(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20 midPreToken;
if (!fromToken.isETH() && destToken.isETH()) {
midPreToken = fromToken;
}
else if (!destToken.isETH() && fromToken.isETH()) {
midPreToken = destToken;
}
if (!midPreToken.isETH()) {
IAaveToken midToken = aaveRegistry.aTokenByToken(midPreToken);
if (midToken != IAaveToken(0)) {
return _calculateUniswapWrapped(
fromToken,
midToken,
destToken,
amount,
parts,
1e18,
flags,
310_000,
670_000
);
}
}
return (new uint256[](parts), 0);
}
function calculateKyber1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xff4b796265722046707200000000000000000000000000000000000000000000 // 0x63825c174ab367968EC60f061753D3bbD36A0D8F
);
}
function calculateKyber2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xffabcd0000000000000000000000000000000000000000000000000000000000 // 0x7a3370075a54B187d7bD5DceBf0ff2B5552d4F7D
);
}
function calculateKyber3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xff4f6e65426974205175616e7400000000000000000000000000000000000000 // 0x4f32BbE8dFc9efD54345Fc936f9fEF1048746fCF
);
}
function calculateKyber4(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
bytes32 reserveId = _kyberReserveIdByTokens(fromToken, destToken);
if (reserveId == 0) {
return (new uint256[](parts), 0);
}
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
reserveId
);
}
function _kyberGetRate(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags,
bytes memory hint
) private view returns(uint256) {
(, bytes memory data) = address(kyberNetworkProxy).staticcall(
abi.encodeWithSelector(
kyberNetworkProxy.getExpectedRateAfterFee.selector,
fromToken,
destToken,
amount,
(flags >> 255) * 10,
hint
)
);
return (data.length == 32) ? abi.decode(data, (uint256)) : 0;
}
function _calculateKyber(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
bytes32 reserveId
) internal view returns(uint256[] memory rets, uint256 gas) {
bytes memory fromHint;
bytes memory destHint;
{
bytes32[] memory reserveIds = new bytes32[](1);
reserveIds[0] = reserveId;
(bool success, bytes memory data) = address(kyberHintHandler).staticcall(
abi.encodeWithSelector(
kyberHintHandler.buildTokenToEthHint.selector,
fromToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
)
);
fromHint = success ? abi.decode(data, (bytes)) : bytes("");
(success, data) = address(kyberHintHandler).staticcall(
abi.encodeWithSelector(
kyberHintHandler.buildEthToTokenHint.selector,
destToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
)
);
destHint = success ? abi.decode(data, (bytes)) : bytes("");
}
uint256 fromTokenDecimals = 10 ** IERC20(fromToken).universalDecimals();
uint256 destTokenDecimals = 10 ** IERC20(destToken).universalDecimals();
rets = new uint256[](parts);
for (uint i = 0; i < parts; i++) {
if (i > 0 && rets[i - 1] == 0) {
break;
}
rets[i] = amount.mul(i + 1).div(parts);
if (!fromToken.isETH()) {
if (fromHint.length == 0) {
rets[i] = 0;
break;
}
uint256 rate = _kyberGetRate(
fromToken,
ETH_ADDRESS,
rets[i],
flags,
fromHint
);
rets[i] = rate.mul(rets[i]).div(fromTokenDecimals);
}
if (!destToken.isETH() && rets[i] > 0) {
if (destHint.length == 0) {
rets[i] = 0;
break;
}
uint256 rate = _kyberGetRate(
ETH_ADDRESS,
destToken,
rets[i],
10,
destHint
);
rets[i] = rate.mul(rets[i]).mul(destTokenDecimals).div(1e36);
}
}
return (rets, 100_000);
}
function calculateBancor(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
return (new uint256[](parts), 0);
// IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork"));
// address[] memory path = bancorFinder.buildBancorPath(
// fromToken.isETH() ? bancorEtherToken : fromToken,
// destToken.isETH() ? bancorEtherToken : destToken
// );
// rets = _linearInterpolation(amount, parts);
// for (uint i = 0; i < parts; i++) {
// (bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)(
// abi.encodeWithSelector(
// bancorNetwork.getReturnByPath.selector,
// path,
// rets[i]
// )
// );
// if (!success || data.length == 0) {
// for (; i < parts; i++) {
// rets[i] = 0;
// }
// break;
// } else {
// (uint256 ret,) = abi.decode(data, (uint256,uint256));
// rets[i] = ret;
// }
// }
// return (rets, path.length.mul(150_000));
}
function calculateOasis(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = _linearInterpolation(amount, parts);
for (uint i = 0; i < parts; i++) {
(bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)(
abi.encodeWithSelector(
oasisExchange.getBuyAmount.selector,
destToken.isETH() ? weth : destToken,
fromToken.isETH() ? weth : fromToken,
rets[i]
)
);
if (!success || data.length == 0) {
for (; i < parts; i++) {
rets[i] = 0;
}
break;
} else {
rets[i] = abi.decode(data, (uint256));
}
}
return (rets, 500_000);
}
function calculateMooniswapMany(
IERC20 fromToken,
IERC20 destToken,
uint256[] memory amounts
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](amounts.length);
IMooniswap mooniswap = mooniswapRegistry.pools(
fromToken.isETH() ? ZERO_ADDRESS : fromToken,
destToken.isETH() ? ZERO_ADDRESS : destToken
);
if (mooniswap == IMooniswap(0)) {
return (rets, 0);
}
uint256 fee = mooniswap.fee();
uint256 fromBalance = mooniswap.getBalanceForAddition(fromToken.isETH() ? ZERO_ADDRESS : fromToken);
uint256 destBalance = mooniswap.getBalanceForRemoval(destToken.isETH() ? ZERO_ADDRESS : destToken);
if (fromBalance == 0 || destBalance == 0) {
return (rets, 0);
}
for (uint i = 0; i < amounts.length; i++) {
uint256 amount = amounts[i].sub(amounts[i].mul(fee).div(1e18));
rets[i] = amount.mul(destBalance).div(
fromBalance.add(amount)
);
}
return (rets, (fromToken.isETH() || destToken.isETH()) ? 80_000 : 110_000);
}
function calculateMooniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
return calculateMooniswapMany(
fromToken,
destToken,
_linearInterpolation(amount, parts)
);
}
function calculateMooniswapOverETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken.isETH() || destToken.isETH()) {
return (new uint256[](parts), 0);
}
(uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, ZERO_ADDRESS, amount, parts, flags);
(rets, gas) = calculateMooniswapMany(ZERO_ADDRESS, destToken, results);
gas = gas.add(gas1);
}
function calculateMooniswapOverDAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == dai || destToken == dai) {
return (new uint256[](parts), 0);
}
(uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, dai, amount, parts, flags);
(rets, gas) = calculateMooniswapMany(dai, destToken, results);
gas = gas.add(gas1);
}
function calculateMooniswapOverUSDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == usdc || destToken == usdc) {
return (new uint256[](parts), 0);
}
(uint256[] memory results, uint256 gas1) = calculateMooniswap(fromToken, usdc, amount, parts, flags);
(rets, gas) = calculateMooniswapMany(usdc, destToken, results);
gas = gas.add(gas1);
}
function calculateUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateUniswapV2(
fromToken,
destToken,
_linearInterpolation(amount, parts),
flags
);
}
function calculateUniswapV2ETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
weth,
destToken,
amount,
parts,
flags
);
}
function calculateUniswapV2DAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == dai || destToken == dai) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
dai,
destToken,
amount,
parts,
flags
);
}
function calculateUniswapV2USDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == usdc || destToken == usdc) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
usdc,
destToken,
amount,
parts,
flags
);
}
function _calculateUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256[] memory amounts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](amounts.length);
IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken;
IERC20 destTokenReal = destToken.isETH() ? weth : destToken;
IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal);
if (exchange != IUniswapV2Exchange(0)) {
uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange));
uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange));
for (uint i = 0; i < amounts.length; i++) {
rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]);
}
return (rets, 50_000);
}
}
function _calculateUniswapV2OverMidToken(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = _linearInterpolation(amount, parts);
uint256 gas1;
uint256 gas2;
(rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags);
(rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags);
return (rets, gas1 + gas2);
}
function _calculateNoReturn(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
this;
return (new uint256[](parts), 0);
}
}
contract OneSplitBaseWrap is IOneSplit, OneSplitRoot {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags // See constants in IOneSplit.sol
) internal {
if (fromToken == destToken) {
return;
}
_swapFloor(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _swapFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 /*flags*/ // See constants in IOneSplit.sol
) internal;
}
contract OneSplit is IOneSplit, OneSplitRoot {
IOneSplitView public oneSplitView;
constructor(IOneSplitView _oneSplitView) public {
oneSplitView = _oneSplitView;
}
function() external payable {
// solium-disable-next-line security/no-tx-origin
require(msg.sender != tx.origin);
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags // See constants in IOneSplit.sol
) public payable returns(uint256 returnAmount) {
if (fromToken == destToken) {
return amount;
}
function(IERC20,IERC20,uint256,uint256)[DEXES_COUNT] memory reserves = [
_swapOnUniswap,
_swapOnNowhere,
_swapOnBancor,
_swapOnOasis,
_swapOnCurveCompound,
_swapOnCurveUSDT,
_swapOnCurveY,
_swapOnCurveBinance,
_swapOnCurveSynthetix,
_swapOnUniswapCompound,
_swapOnUniswapChai,
_swapOnUniswapAave,
_swapOnMooniswap,
_swapOnUniswapV2,
_swapOnUniswapV2ETH,
_swapOnUniswapV2DAI,
_swapOnUniswapV2USDC,
_swapOnCurvePAX,
_swapOnCurveRenBTC,
_swapOnCurveTBTC,
_swapOnDforceSwap,
_swapOnShell,
_swapOnMStableMUSD,
_swapOnCurveSBTC,
_swapOnBalancer1,
_swapOnBalancer2,
_swapOnBalancer3,
_swapOnKyber1,
_swapOnKyber2,
_swapOnKyber3,
_swapOnKyber4,
_swapOnMooniswapETH,
_swapOnMooniswapDAI,
_swapOnMooniswapUSDC
];
require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size");
uint256 parts = 0;
uint256 lastNonZeroIndex = 0;
for (uint i = 0; i < distribution.length; i++) {
if (distribution[i] > 0) {
parts = parts.add(distribution[i]);
lastNonZeroIndex = i;
}
}
if (parts == 0) {
if (fromToken.isETH()) {
msg.sender.transfer(msg.value);
return msg.value;
}
return amount;
}
fromToken.universalTransferFrom(msg.sender, address(this), amount);
uint256 remainingAmount = fromToken.universalBalanceOf(address(this));
for (uint i = 0; i < distribution.length; i++) {
if (distribution[i] == 0) {
continue;
}
uint256 swapAmount = amount.mul(distribution[i]).div(parts);
if (i == lastNonZeroIndex) {
swapAmount = remainingAmount;
}
remainingAmount -= swapAmount;
reserves[i](fromToken, destToken, swapAmount, flags);
}
returnAmount = destToken.universalBalanceOf(address(this));
require(returnAmount >= minReturn, "OneSplit: Return amount was not enough");
destToken.universalTransfer(msg.sender, returnAmount);
fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this)));
}
// Swap helpers
function _swapOnCurveCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0);
int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveCompound), amount);
curveCompound.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveUSDT(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveUSDT), amount);
curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveY(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == tusd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == tusd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveY), amount);
curveY.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveBinance(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == busd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == busd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveBinance), amount);
curveBinance.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveSynthetix(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == susd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == susd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveSynthetix), amount);
curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurvePAX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == pax ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == pax ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curvePAX), amount);
curvePAX.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnShell(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(shell), amount);
shell.swapByOrigin(
address(fromToken),
address(destToken),
amount,
0,
now + 50
);
}
function _swapOnMStableMUSD(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(musd), amount);
musd.swap(
fromToken,
destToken,
amount,
address(this)
);
}
function _swapOnCurveRenBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == renbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0);
int128 j = (destToken == renbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveRenBTC), amount);
curveRenBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnCurveTBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == tbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0) +
(fromToken == hbtc ? 3 : 0);
int128 j = (destToken == tbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0) +
(destToken == hbtc ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveTBTC), amount);
curveTBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnCurveSBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == renbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0) +
(fromToken == sbtc ? 3 : 0);
int128 j = (destToken == renbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0) +
(destToken == sbtc ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveSBTC), amount);
curveSBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnDforceSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(dforceSwap), amount);
dforceSwap.swap(fromToken, destToken, amount);
}
function _swapOnUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
uint256 returnAmount = amount;
if (!fromToken.isETH()) {
IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken);
if (fromExchange != IUniswapExchange(0)) {
fromToken.universalApprove(address(fromExchange), returnAmount);
returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now);
}
}
if (!destToken.isETH()) {
IUniswapExchange toExchange = uniswapFactory.getExchange(destToken);
if (toExchange != IUniswapExchange(0)) {
returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now);
}
}
}
function _swapOnUniswapCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (!fromToken.isETH()) {
ICompoundToken fromCompound = compoundRegistry.cTokenByToken(fromToken);
fromToken.universalApprove(address(fromCompound), amount);
fromCompound.mint(amount);
_swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this)), flags);
return;
}
if (!destToken.isETH()) {
ICompoundToken toCompound = compoundRegistry.cTokenByToken(destToken);
_swapOnUniswap(fromToken, IERC20(toCompound), amount, flags);
toCompound.redeem(IERC20(toCompound).universalBalanceOf(address(this)));
destToken.universalBalanceOf(address(this));
return;
}
}
function _swapOnUniswapChai(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (fromToken == dai) {
fromToken.universalApprove(address(chai), amount);
chai.join(address(this), amount);
_swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this)), flags);
return;
}
if (destToken == dai) {
_swapOnUniswap(fromToken, IERC20(chai), amount, flags);
chai.exit(address(this), chai.balanceOf(address(this)));
return;
}
}
function _swapOnUniswapAave(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (!fromToken.isETH()) {
IAaveToken fromAave = aaveRegistry.aTokenByToken(fromToken);
fromToken.universalApprove(aave.core(), amount);
aave.deposit(fromToken, amount, 1101);
_swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this)), flags);
return;
}
if (!destToken.isETH()) {
IAaveToken toAave = aaveRegistry.aTokenByToken(destToken);
_swapOnUniswap(fromToken, IERC20(toAave), amount, flags);
toAave.redeem(toAave.balanceOf(address(this)));
return;
}
}
function _swapOnMooniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
IMooniswap mooniswap = mooniswapRegistry.pools(
fromToken.isETH() ? ZERO_ADDRESS : fromToken,
destToken.isETH() ? ZERO_ADDRESS : destToken
);
fromToken.universalApprove(address(mooniswap), amount);
mooniswap.swap.value(fromToken.isETH() ? amount : 0)(
fromToken.isETH() ? ZERO_ADDRESS : fromToken,
destToken.isETH() ? ZERO_ADDRESS : destToken,
amount,
0,
0x68a17B587CAF4f9329f0e372e3A78D23A46De6b5
);
}
function _swapOnMooniswapETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnMooniswap(fromToken, ZERO_ADDRESS, amount, flags);
_swapOnMooniswap(ZERO_ADDRESS, destToken, address(this).balance, flags);
}
function _swapOnMooniswapDAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnMooniswap(fromToken, dai, amount, flags);
_swapOnMooniswap(dai, destToken, dai.balanceOf(address(this)), flags);
}
function _swapOnMooniswapUSDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnMooniswap(fromToken, usdc, amount, flags);
_swapOnMooniswap(usdc, destToken, usdc.balanceOf(address(this)), flags);
}
function _swapOnNowhere(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 /*flags*/
) internal {
revert("This source was deprecated");
}
function _swapOnKyber1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xff4b796265722046707200000000000000000000000000000000000000000000
);
}
function _swapOnKyber2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xffabcd0000000000000000000000000000000000000000000000000000000000
);
}
function _swapOnKyber3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xff4f6e65426974205175616e7400000000000000000000000000000000000000
);
}
function _swapOnKyber4(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
_kyberReserveIdByTokens(fromToken, destToken)
);
}
function _swapOnKyber(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags,
bytes32 reserveId
) internal {
uint256 returnAmount = amount;
bytes32[] memory reserveIds = new bytes32[](1);
reserveIds[0] = reserveId;
if (!fromToken.isETH()) {
bytes memory fromHint = kyberHintHandler.buildTokenToEthHint(
fromToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
);
fromToken.universalApprove(address(kyberNetworkProxy), amount);
returnAmount = kyberNetworkProxy.tradeWithHintAndFee(
fromToken,
returnAmount,
ETH_ADDRESS,
address(this),
uint256(-1),
0,
0x68a17B587CAF4f9329f0e372e3A78D23A46De6b5,
(flags >> 255) * 10,
fromHint
);
}
if (!destToken.isETH()) {
bytes memory destHint = kyberHintHandler.buildEthToTokenHint(
destToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
);
returnAmount = kyberNetworkProxy.tradeWithHintAndFee.value(returnAmount)(
ETH_ADDRESS,
returnAmount,
destToken,
address(this),
uint256(-1),
0,
0x68a17B587CAF4f9329f0e372e3A78D23A46De6b5,
(flags >> 255) * 10,
destHint
);
}
}
function _swapOnBancor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork"));
address[] memory path = bancorNetworkPathFinder.generatePath(
fromToken.isETH() ? bancorEtherToken : fromToken,
destToken.isETH() ? bancorEtherToken : destToken
);
fromToken.universalApprove(address(bancorNetwork), amount);
bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1);
}
function _swapOnOasis(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
IERC20 approveToken = fromToken.isETH() ? weth : fromToken;
approveToken.universalApprove(address(oasisExchange), amount);
oasisExchange.sellAllAmount(
fromToken.isETH() ? weth : fromToken,
amount,
destToken.isETH() ? weth : destToken,
1
);
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnUniswapV2Internal(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal returns(uint256 returnAmount) {
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken;
IERC20 toTokenReal = destToken.isETH() ? weth : destToken;
IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal);
bool needSync;
bool needSkim;
(returnAmount, needSync, needSkim) = exchange.getReturn(fromTokenReal, toTokenReal, amount);
if (needSync) {
exchange.sync();
}
else if (needSkim) {
exchange.skim(0x68a17B587CAF4f9329f0e372e3A78D23A46De6b5);
}
fromTokenReal.universalTransfer(address(exchange), amount);
if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) {
exchange.swap(0, returnAmount, address(this), "");
} else {
exchange.swap(returnAmount, 0, address(this), "");
}
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnUniswapV2OverMid(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2Internal(
midToken,
destToken,
_swapOnUniswapV2Internal(
fromToken,
midToken,
amount,
flags
),
flags
);
}
function _swapOnUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2Internal(
fromToken,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2ETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
weth,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2DAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
dai,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2USDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
usdc,
destToken,
amount,
flags
);
}
function _swapOnBalancerX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/,
uint256 poolIndex
) internal {
address[] memory pools = balancerRegistry.getBestPoolsWithLimit(
address(fromToken.isETH() ? weth : fromToken),
address(destToken.isETH() ? weth : destToken),
poolIndex + 1
);
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
(fromToken.isETH() ? weth : fromToken).universalApprove(pools[poolIndex], amount);
IBalancerPool(pools[poolIndex]).swapExactAmountIn(
fromToken.isETH() ? weth : fromToken,
amount,
destToken.isETH() ? weth : destToken,
0,
uint256(-1)
);
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnBalancer1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 0);
}
function _swapOnBalancer2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 1);
}
function _swapOnBalancer3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 2);
}
}
// File: contracts/OneSplitCompound.sol
pragma solidity ^0.5.0;
contract OneSplitCompoundView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _compoundGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _compoundGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) {
IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken)));
if (underlying != IERC20(0)) {
uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored();
(returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn(
underlying,
destToken,
amount.mul(compoundRate).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken)));
if (underlying != IERC20(0)) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18)
);
return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitCompound is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_compoundSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _compoundSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) {
IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken)));
if (underlying != IERC20(0)) {
ICompoundToken(address(fromToken)).redeem(amount);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
return _compoundSwap(
underlying,
destToken,
underlyingAmount,
distribution,
flags
);
}
underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken)));
if (underlying != IERC20(0)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
if (underlying.isETH()) {
cETH.mint.value(underlyingAmount)();
} else {
underlying.universalApprove(address(destToken), underlyingAmount);
ICompoundToken(address(destToken)).mint(underlyingAmount);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IFulcrum.sol
pragma solidity ^0.5.0;
contract IFulcrumToken is IERC20 {
function tokenPrice() external view returns (uint256);
function loanTokenAddress() external view returns (address);
function mintWithEther(address receiver) external payable returns (uint256 mintAmount);
function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);
function burnToEther(address receiver, uint256 burnAmount)
external
returns (uint256 loanAmountPaid);
function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);
}
// File: contracts/OneSplitFulcrum.sol
pragma solidity ^0.5.0;
contract OneSplitFulcrumBase {
using UniversalERC20 for IERC20;
function _isFulcrumToken(IERC20 token) internal view returns(IERC20) {
if (token.isETH()) {
return IERC20(-1);
}
(bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature(
"name()"
));
if (!success) {
return IERC20(-1);
}
bool foundBZX = false;
for (uint i = 0; i + 6 < data.length; i++) {
if (data[i + 0] == "F" &&
data[i + 1] == "u" &&
data[i + 2] == "l" &&
data[i + 3] == "c" &&
data[i + 4] == "r" &&
data[i + 5] == "u" &&
data[i + 6] == "m")
{
foundBZX = true;
break;
}
}
if (!foundBZX) {
return IERC20(-1);
}
(success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector(
IFulcrumToken(address(token)).loanTokenAddress.selector
));
if (!success) {
return IERC20(-1);
}
return abi.decode(data, (IERC20));
}
}
contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _fulcrumGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _fulcrumGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) {
IERC20 underlying = _isFulcrumToken(fromToken);
if (underlying != IERC20(-1)) {
uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice();
(returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn(
underlying,
destToken,
amount.mul(fulcrumRate).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 381_000, distribution);
}
underlying = _isFulcrumToken(destToken);
if (underlying != IERC20(-1)) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18)
);
return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_fulcrumSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _fulcrumSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) {
IERC20 underlying = _isFulcrumToken(fromToken);
if (underlying != IERC20(-1)) {
if (underlying.isETH()) {
IFulcrumToken(address(fromToken)).burnToEther(address(this), amount);
} else {
IFulcrumToken(address(fromToken)).burn(address(this), amount);
}
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
return super._swap(
underlying,
destToken,
underlyingAmount,
distribution,
flags
);
}
underlying = _isFulcrumToken(destToken);
if (underlying != IERC20(-1)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
if (underlying.isETH()) {
IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this));
} else {
underlying.universalApprove(address(destToken), underlyingAmount);
IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitChai.sol
pragma solidity ^0.5.0;
contract OneSplitChaiView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) {
if (fromToken == IERC20(chai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
dai,
destToken,
chai.chaiToDai(amount),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 197_000, distribution);
}
if (destToken == IERC20(chai)) {
uint256 price = chai.chaiPrice();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
dai,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice.mul(1e18).div(price)
);
return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitChai is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) {
if (fromToken == IERC20(chai)) {
chai.exit(address(this), amount);
return super._swap(
dai,
destToken,
dai.balanceOf(address(this)),
distribution,
flags
);
}
if (destToken == IERC20(chai)) {
super._swap(
fromToken,
dai,
amount,
distribution,
flags
);
uint256 daiBalance = dai.balanceOf(address(this));
dai.universalApprove(address(chai), daiBalance);
chai.join(address(this), daiBalance);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IBdai.sol
pragma solidity ^0.5.0;
contract IBdai is IERC20 {
function join(uint256) external;
function exit(uint256) external;
}
// File: contracts/OneSplitBdai.sol
pragma solidity ^0.5.0;
contract OneSplitBdaiBase {
IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8);
IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f);
}
contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) {
if (fromToken == IERC20(bdai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
dai,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 227_000, distribution);
}
if (destToken == IERC20(bdai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
dai,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) {
if (fromToken == IERC20(bdai)) {
bdai.exit(amount);
uint256 btuBalance = btu.balanceOf(address(this));
if (btuBalance > 0) {
(,uint256[] memory btuDistribution) = getExpectedReturn(
btu,
destToken,
btuBalance,
1,
flags
);
_swap(
btu,
destToken,
btuBalance,
btuDistribution,
flags
);
}
return super._swap(
dai,
destToken,
amount,
distribution,
flags
);
}
if (destToken == IERC20(bdai)) {
super._swap(fromToken, dai, amount, distribution, flags);
uint256 daiBalance = dai.balanceOf(address(this));
dai.universalApprove(address(bdai), daiBalance);
bdai.join(daiBalance);
return;
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/interface/IIearn.sol
pragma solidity ^0.5.0;
contract IIearn is IERC20 {
function token() external view returns(IERC20);
function calcPoolValueInToken() external view returns(uint256);
function deposit(uint256 _amount) external;
function withdraw(uint256 _shares) external;
}
// File: contracts/OneSplitIearn.sol
pragma solidity ^0.5.0;
contract OneSplitIearnBase {
function _yTokens() internal pure returns(IIearn[13] memory) {
return [
IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01),
IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9),
IIearn(0x73a052500105205d34Daf004eAb301916DA8190f),
IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D),
IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e),
IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600),
IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE),
IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32),
IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447),
IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951),
IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc),
IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E),
IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59)
];
}
}
contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _iearnGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _iearnGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) {
IIearn[13] memory yTokens = _yTokens();
for (uint i = 0; i < yTokens.length; i++) {
if (fromToken == IERC20(yTokens[i])) {
(returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn(
yTokens[i].token(),
destToken,
amount
.mul(yTokens[i].calcPoolValueInToken())
.div(yTokens[i].totalSupply()),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 260_000, distribution);
}
}
for (uint i = 0; i < yTokens.length; i++) {
if (destToken == IERC20(yTokens[i])) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
IERC20 token = yTokens[i].token();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
token,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice
.mul(yTokens[i].calcPoolValueInToken())
.div(yTokens[i].totalSupply())
);
return(
returnAmount
.mul(yTokens[i].totalSupply())
.div(yTokens[i].calcPoolValueInToken()),
estimateGasAmount + 743_000,
distribution
);
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_iearnSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _iearnSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) {
IIearn[13] memory yTokens = _yTokens();
for (uint i = 0; i < yTokens.length; i++) {
if (fromToken == IERC20(yTokens[i])) {
IERC20 underlying = yTokens[i].token();
yTokens[i].withdraw(amount);
_iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags);
return;
}
}
for (uint i = 0; i < yTokens.length; i++) {
if (destToken == IERC20(yTokens[i])) {
IERC20 underlying = yTokens[i].token();
super._swap(fromToken, underlying, amount, distribution, flags);
uint256 underlyingBalance = underlying.balanceOf(address(this));
underlying.universalApprove(address(yTokens[i]), underlyingBalance);
yTokens[i].deposit(underlyingBalance);
return;
}
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/interface/IIdle.sol
pragma solidity ^0.5.0;
contract IIdle is IERC20 {
function token()
external view returns (IERC20);
function tokenPrice()
external view returns (uint256);
function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts)
external returns (uint256 mintedTokens);
function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts)
external returns (uint256 redeemedTokens);
}
// File: contracts/OneSplitIdle.sol
pragma solidity ^0.5.0;
contract OneSplitIdleBase {
function _idleTokens() internal pure returns(IIdle[8] memory) {
// https://developers.idle.finance/contracts-and-codebase
return [
// V3
IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934),
IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6),
IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D),
IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB),
IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C),
IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B),
// V2
IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD),
IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991)
];
}
}
contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _idleGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _idleGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) {
IIdle[8] memory tokens = _idleTokens();
for (uint i = 0; i < tokens.length; i++) {
if (fromToken == IERC20(tokens[i])) {
(returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn(
tokens[i].token(),
destToken,
amount.mul(tokens[i].tokenPrice()).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 2_400_000, distribution);
}
}
for (uint i = 0; i < tokens.length; i++) {
if (destToken == IERC20(tokens[i])) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 _price = tokens[i].tokenPrice();
IERC20 token = tokens[i].token();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
token,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(_price).div(1e18)
);
return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution);
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_idleSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _idleSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) {
IIdle[8] memory tokens = _idleTokens();
for (uint i = 0; i < tokens.length; i++) {
if (fromToken == IERC20(tokens[i])) {
IERC20 underlying = tokens[i].token();
uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0));
_idleSwap(underlying, destToken, minted, distribution, flags);
return;
}
}
for (uint i = 0; i < tokens.length; i++) {
if (destToken == IERC20(tokens[i])) {
IERC20 underlying = tokens[i].token();
super._swap(fromToken, underlying, amount, distribution, flags);
uint256 underlyingBalance = underlying.balanceOf(address(this));
underlying.universalApprove(address(tokens[i]), underlyingBalance);
tokens[i].mintIdleToken(underlyingBalance, new uint256[](0));
return;
}
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/OneSplitAave.sol
pragma solidity ^0.5.0;
contract OneSplitAaveView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _aaveGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _aaveGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) {
IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken)));
if (underlying != IERC20(0)) {
(returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn(
underlying,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 670_000, distribution);
}
underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken)));
if (underlying != IERC20(0)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 310_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitAave is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_aaveSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _aaveSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) {
IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken)));
if (underlying != IERC20(0)) {
IAaveToken(address(fromToken)).redeem(amount);
return _aaveSwap(
underlying,
destToken,
amount,
distribution,
flags
);
}
underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken)));
if (underlying != IERC20(0)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
underlying.universalApprove(aave.core(), underlyingAmount);
aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)(
underlying.isETH() ? ETH_ADDRESS : underlying,
underlyingAmount,
1101
);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitWeth.sol
pragma solidity ^0.5.0;
contract OneSplitWethView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _wethGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _wethGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) {
if (fromToken == weth || fromToken == bancorEtherToken) {
return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice);
}
if (destToken == weth || destToken == bancorEtherToken) {
return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitWeth is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_wethSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _wethSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) {
if (fromToken == weth) {
weth.withdraw(weth.balanceOf(address(this)));
super._swap(
ETH_ADDRESS,
destToken,
amount,
distribution,
flags
);
return;
}
if (fromToken == bancorEtherToken) {
bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this)));
super._swap(
ETH_ADDRESS,
destToken,
amount,
distribution,
flags
);
return;
}
if (destToken == weth) {
_wethSwap(
fromToken,
ETH_ADDRESS,
amount,
distribution,
flags
);
weth.deposit.value(address(this).balance)();
return;
}
if (destToken == bancorEtherToken) {
_wethSwap(
fromToken,
ETH_ADDRESS,
amount,
distribution,
flags
);
bancorEtherToken.deposit.value(address(this).balance)();
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitMStable.sol
pragma solidity ^0.5.0;
contract OneSplitMStableView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) {
if (fromToken == IERC20(musd)) {
{
(bool valid1,, uint256 res1,) = musd_helper.getRedeemValidity(musd, amount, destToken);
if (valid1) {
return (res1, 300_000, new uint256[](DEXES_COUNT));
}
}
(bool valid,, address token) = musd_helper.suggestRedeemAsset(musd);
if (valid) {
(,, returnAmount,) = musd_helper.getRedeemValidity(musd, amount, IERC20(token));
if (IERC20(token) != destToken) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
IERC20(token),
destToken,
returnAmount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
} else {
distribution = new uint256[](DEXES_COUNT);
}
return (returnAmount, estimateGasAmount + 300_000, distribution);
}
}
if (destToken == IERC20(musd)) {
if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) {
(,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount);
return (returnAmount, 300_000, new uint256[](DEXES_COUNT));
}
else {
IERC20 _destToken = destToken;
(bool valid,, address token) = musd_helper.suggestMintAsset(_destToken);
if (valid) {
if (IERC20(token) != fromToken) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
IERC20(token),
amount,
parts,
flags,
_scaleDestTokenEthPriceTimesGasPrice(
_destToken,
IERC20(token),
destTokenEthPriceTimesGasPrice
)
);
} else {
returnAmount = amount;
}
(,, returnAmount) = musd.getSwapOutput(IERC20(token), _destToken, returnAmount);
return (returnAmount, estimateGasAmount + 300_000, distribution);
}
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitMStable is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) {
if (fromToken == IERC20(musd)) {
if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) {
(,,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken);
musd.redeem(
destToken,
result
);
}
else {
(,,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai);
musd.redeem(
dai,
result
);
super._swap(
dai,
destToken,
dai.balanceOf(address(this)),
distribution,
flags
);
}
return;
}
if (destToken == IERC20(musd)) {
if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) {
fromToken.universalApprove(address(musd), amount);
musd.swap(
fromToken,
destToken,
amount,
address(this)
);
}
else {
super._swap(
fromToken,
dai,
amount,
distribution,
flags
);
musd.swap(
dai,
destToken,
dai.balanceOf(address(this)),
address(this)
);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IDMM.sol
pragma solidity ^0.5.0;
interface IDMMController {
function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20);
}
contract IDMM is IERC20 {
function getCurrentExchangeRate() public view returns(uint256);
function mint(uint256 underlyingAmount) public returns(uint256);
function redeem(uint256 amount) public returns(uint256);
}
// File: contracts/OneSplitDMM.sol
pragma solidity ^0.5.0;
contract OneSplitDMMBase {
IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2);
function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) {
(bool success, bytes memory data) = address(_dmmController).staticcall(
abi.encodeWithSelector(
_dmmController.getUnderlyingTokenForDmm.selector,
token
)
);
if (!success || data.length == 0) {
return IERC20(-1);
}
return abi.decode(data, (IERC20));
}
function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) {
(bool success, bytes memory data) = address(dmm).staticcall(
abi.encodeWithSelector(
dmm.getCurrentExchangeRate.selector
)
);
if (!success || data.length == 0) {
return 0;
}
return abi.decode(data, (uint256));
}
}
contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _dmmGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _dmmGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) {
IERC20 underlying = _getDMMUnderlyingToken(fromToken);
if (underlying != IERC20(-1)) {
if (underlying == weth) {
underlying = ETH_ADDRESS;
}
IERC20 _fromToken = fromToken;
(returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn(
underlying,
destToken,
amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
underlying = _getDMMUnderlyingToken(destToken);
if (underlying != IERC20(-1)) {
if (underlying == weth) {
underlying = ETH_ADDRESS;
}
uint256 price = _getDMMExchangeRate(IDMM(address(destToken)));
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice.mul(price).div(1e18)
);
return (
returnAmount.mul(1e18).div(price),
estimateGasAmount + 430_000,
distribution
);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_dmmSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _dmmSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) {
IERC20 underlying = _getDMMUnderlyingToken(fromToken);
if (underlying != IERC20(-1)) {
IDMM(address(fromToken)).redeem(amount);
uint256 balance = underlying.universalBalanceOf(address(this));
if (underlying == weth) {
weth.withdraw(balance);
}
_dmmSwap(
(underlying == weth) ? ETH_ADDRESS : underlying,
destToken,
balance,
distribution,
flags
);
}
underlying = _getDMMUnderlyingToken(destToken);
if (underlying != IERC20(-1)) {
super._swap(
fromToken,
(underlying == weth) ? ETH_ADDRESS : underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this));
if (underlying == weth) {
weth.deposit.value(underlyingAmount);
}
underlying.universalApprove(address(destToken), underlyingAmount);
IDMM(address(destToken)).mint(underlyingAmount);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitMooniswapPoolToken.sol
pragma solidity ^0.5.0;
contract OneSplitMooniswapTokenBase {
using SafeMath for uint256;
using Math for uint256;
using UniversalERC20 for IERC20;
struct TokenInfo {
IERC20 token;
uint256 reserve;
}
struct PoolDetails {
TokenInfo[2] tokens;
uint256 totalSupply;
}
function _getPoolDetails(IMooniswap pool) internal view returns (PoolDetails memory details) {
for (uint i = 0; i < 2; i++) {
IERC20 token = pool.tokens(i);
details.tokens[i] = TokenInfo({
token: token,
reserve: token.universalBalanceOf(address(pool))
});
}
details.totalSupply = IERC20(address(pool)).totalSupply();
}
}
contract OneSplitMooniswapTokenView is OneSplitViewWrapBase, OneSplitMooniswapTokenBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 toToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns (
uint256 returnAmount,
uint256,
uint256[] memory distribution
)
{
if (fromToken.eq(toToken)) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (!flags.check(FLAG_DISABLE_MOONISWAP_POOL_TOKEN)) {
bool isPoolTokenFrom = mooniswapRegistry.isPool(address(fromToken));
bool isPoolTokenTo = mooniswapRegistry.isPool(address(toToken));
if (isPoolTokenFrom && isPoolTokenTo) {
(
uint256 returnETHAmount,
uint256[] memory poolTokenFromDistribution
) = _getExpectedReturnFromMooniswapPoolToken(
fromToken,
ETH_ADDRESS,
amount,
parts,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
(
uint256 returnPoolTokenToAmount,
uint256[] memory poolTokenToDistribution
) = _getExpectedReturnToMooniswapPoolToken(
ETH_ADDRESS,
toToken,
returnETHAmount,
parts,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
for (uint i = 0; i < poolTokenToDistribution.length; i++) {
poolTokenFromDistribution[i] |= poolTokenToDistribution[i] << 128;
}
return (returnPoolTokenToAmount, 0, poolTokenFromDistribution);
}
if (isPoolTokenFrom) {
(returnAmount, distribution) = _getExpectedReturnFromMooniswapPoolToken(
fromToken,
toToken,
amount,
parts,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
return (returnAmount, 0, distribution);
}
if (isPoolTokenTo) {
(returnAmount, distribution) = _getExpectedReturnToMooniswapPoolToken(
fromToken,
toToken,
amount,
parts,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
return (returnAmount, 0, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
toToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _getExpectedReturnFromMooniswapPoolToken(
IERC20 poolToken,
IERC20 toToken,
uint256 amount,
uint256 parts,
uint256 flags
)
private
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
distribution = new uint256[](DEXES_COUNT);
PoolDetails memory details = _getPoolDetails(IMooniswap(address(poolToken)));
for (uint i = 0; i < 2; i++) {
uint256 exchangeAmount = amount
.mul(details.tokens[i].reserve)
.div(details.totalSupply);
if (toToken.eq(details.tokens[i].token)) {
returnAmount = returnAmount.add(exchangeAmount);
continue;
}
(uint256 ret, ,uint256[] memory dist) = super.getExpectedReturnWithGas(
details.tokens[i].token,
toToken,
exchangeAmount,
parts,
flags,
0
);
returnAmount = returnAmount.add(ret);
for (uint j = 0; j < distribution.length; j++) {
distribution[j] |= dist[j] << (i * 8);
}
}
return (returnAmount, distribution);
}
function _getExpectedReturnToMooniswapPoolToken(
IERC20 fromToken,
IERC20 poolToken,
uint256 amount,
uint256 parts,
uint256 flags
)
private
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
distribution = new uint256[](DEXES_COUNT);
PoolDetails memory details = _getPoolDetails(IMooniswap(address(poolToken)));
// will overwritten to liquidity amounts
uint256[2] memory amounts;
amounts[0] = amount.div(2);
amounts[1] = amount.sub(amounts[0]);
uint256[] memory dist = new uint256[](distribution.length);
for (uint i = 0; i < 2; i++) {
if (fromToken.eq(details.tokens[i].token)) {
continue;
}
(amounts[i], ,dist) = super.getExpectedReturnWithGas(
fromToken,
details.tokens[i].token,
amounts[i],
parts,
flags,
0
);
for (uint j = 0; j < distribution.length; j++) {
distribution[j] |= dist[j] << (i * 8);
}
}
returnAmount = uint256(-1);
for (uint i = 0; i < 2; i++) {
returnAmount = Math.min(
returnAmount,
details.totalSupply.mul(amounts[i]).div(details.tokens[i].reserve)
);
}
return (
returnAmount,
distribution
);
}
}
contract OneSplitMooniswapToken is OneSplitBaseWrap, OneSplitMooniswapTokenBase {
function _swap(
IERC20 fromToken,
IERC20 toToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken.eq(toToken)) {
return;
}
if (!flags.check(FLAG_DISABLE_MOONISWAP_POOL_TOKEN)) {
bool isPoolTokenFrom = mooniswapRegistry.isPool(address(fromToken));
bool isPoolTokenTo = mooniswapRegistry.isPool(address(toToken));
if (isPoolTokenFrom && isPoolTokenTo) {
uint256[] memory dist = new uint256[](distribution.length);
for (uint i = 0; i < distribution.length; i++) {
dist[i] = distribution[i] & ((1 << 128) - 1);
}
uint256 ethBalanceBefore = ETH_ADDRESS.universalBalanceOf(address(this));
_swapFromMooniswapToken(
fromToken,
ETH_ADDRESS,
amount,
dist,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
for (uint i = 0; i < distribution.length; i++) {
dist[i] = distribution[i] >> 128;
}
uint256 ethBalanceAfter = ETH_ADDRESS.universalBalanceOf(address(this));
return _swapToMooniswapToken(
ETH_ADDRESS,
toToken,
ethBalanceAfter.sub(ethBalanceBefore),
dist,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
}
if (isPoolTokenFrom) {
return _swapFromMooniswapToken(
fromToken,
toToken,
amount,
distribution,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
}
if (isPoolTokenTo) {
return _swapToMooniswapToken(
fromToken,
toToken,
amount,
distribution,
FLAG_DISABLE_MOONISWAP_POOL_TOKEN
);
}
}
return super._swap(
fromToken,
toToken,
amount,
distribution,
flags
);
}
function _swapFromMooniswapToken(
IERC20 poolToken,
IERC20 toToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
IERC20[2] memory tokens = [
IMooniswap(address(poolToken)).tokens(0),
IMooniswap(address(poolToken)).tokens(1)
];
IMooniswap(address(poolToken)).withdraw(
amount,
new uint256[](0)
);
uint256[] memory dist = new uint256[](distribution.length);
for (uint i = 0; i < 2; i++) {
if (toToken.eq(tokens[i])) {
continue;
}
for (uint j = 0; j < distribution.length; j++) {
dist[j] = (distribution[j] >> (i * 8)) & 0xFF;
}
super._swap(
tokens[i],
toToken,
tokens[i].universalBalanceOf(address(this)),
dist,
flags
);
}
}
function _swapToMooniswapToken(
IERC20 fromToken,
IERC20 poolToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
IERC20[2] memory tokens = [
IMooniswap(address(poolToken)).tokens(0),
IMooniswap(address(poolToken)).tokens(1)
];
// will overwritten to liquidity amounts
uint256[] memory amounts = new uint256[](2);
amounts[0] = amount.div(2);
amounts[1] = amount.sub(amounts[0]);
uint256[] memory dist = new uint256[](distribution.length);
for (uint i = 0; i < 2; i++) {
if (fromToken.eq(tokens[i])) {
continue;
}
for (uint j = 0; j < distribution.length; j++) {
dist[j] = (distribution[j] >> (i * 8)) & 0xFF;
}
super._swap(
fromToken,
tokens[i],
amounts[i],
dist,
flags
);
amounts[i] = tokens[i].universalBalanceOf(address(this));
tokens[i].universalApprove(address(poolToken), amounts[i]);
}
uint256 ethValue = (tokens[0].isETH() ? amounts[0] : 0) + (tokens[1].isETH() ? amounts[1] : 0);
IMooniswap(address(poolToken)).deposit.value(ethValue)(
amounts,
new uint256[](2)
);
for (uint i = 0; i < 2; i++) {
tokens[i].universalTransfer(
msg.sender,
tokens[i].universalBalanceOf(address(this))
);
}
}
}
// File: contracts/OneSplit.sol
pragma solidity ^0.5.0;
contract OneSplitViewWrap is
OneSplitViewWrapBase,
OneSplitMStableView,
OneSplitChaiView,
OneSplitBdaiView,
OneSplitAaveView,
OneSplitFulcrumView,
OneSplitCompoundView,
OneSplitIearnView,
OneSplitIdleView,
OneSplitWethView,
OneSplitDMMView,
OneSplitMooniswapTokenView
{
IOneSplitView public oneSplitView;
constructor(IOneSplitView _oneSplit) public {
oneSplitView = _oneSplit;
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _getExpectedReturnRespectingGasFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitWrap is
OneSplitBaseWrap,
OneSplitMStable,
OneSplitChai,
OneSplitBdai,
OneSplitAave,
OneSplitFulcrum,
OneSplitCompound,
OneSplitIearn,
OneSplitIdle,
OneSplitWeth,
OneSplitDMM,
OneSplitMooniswapToken
{
IOneSplitView public oneSplitView;
IOneSplit public oneSplit;
constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public {
oneSplitView = _oneSplitView;
oneSplit = _oneSplit;
}
function() external payable {
// solium-disable-next-line security/no-tx-origin
require(msg.sender != tx.origin);
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function getExpectedReturnWithGasMulti(
IERC20[] memory tokens,
uint256 amount,
uint256[] memory parts,
uint256[] memory flags,
uint256[] memory destTokenEthPriceTimesGasPrices
)
public
view
returns(
uint256[] memory returnAmounts,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
uint256[] memory dist;
returnAmounts = new uint256[](tokens.length - 1);
for (uint i = 1; i < tokens.length; i++) {
if (tokens[i - 1] == tokens[i]) {
returnAmounts[i - 1] = (i == 1) ? amount : returnAmounts[i - 2];
continue;
}
IERC20[] memory _tokens = tokens;
(
returnAmounts[i - 1],
amount,
dist
) = getExpectedReturnWithGas(
_tokens[i - 1],
_tokens[i],
(i == 1) ? amount : returnAmounts[i - 2],
parts[i - 1],
flags[i - 1],
destTokenEthPriceTimesGasPrices[i - 1]
);
estimateGasAmount = estimateGasAmount.add(amount);
if (distribution.length == 0) {
distribution = new uint256[](dist.length);
}
for (uint j = 0; j < distribution.length; j++) {
distribution[j] = distribution[j].add(dist[j] << (8 * (i - 1)));
}
}
}
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags
) public payable returns(uint256 returnAmount) {
fromToken.universalTransferFrom(msg.sender, address(this), amount);
uint256 confirmed = fromToken.universalBalanceOf(address(this));
_swap(fromToken, destToken, confirmed, distribution, flags);
returnAmount = destToken.universalBalanceOf(address(this));
require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn");
destToken.universalTransfer(msg.sender, returnAmount);
fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this)));
}
function swapMulti(
IERC20[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256[] memory flags
) public payable returns(uint256 returnAmount) {
tokens[0].universalTransferFrom(msg.sender, address(this), amount);
returnAmount = tokens[0].universalBalanceOf(address(this));
for (uint i = 1; i < tokens.length; i++) {
if (tokens[i - 1] == tokens[i]) {
continue;
}
uint256[] memory dist = new uint256[](distribution.length);
for (uint j = 0; j < distribution.length; j++) {
dist[j] = (distribution[j] >> (8 * (i - 1))) & 0xFF;
}
_swap(
tokens[i - 1],
tokens[i],
returnAmount,
dist,
flags[i - 1]
);
returnAmount = tokens[i].universalBalanceOf(address(this));
tokens[i - 1].universalTransfer(msg.sender, tokens[i - 1].universalBalanceOf(address(this)));
}
require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn");
tokens[tokens.length - 1].universalTransfer(msg.sender, returnAmount);
}
function _swapFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
fromToken.universalApprove(address(oneSplit), amount);
oneSplit.swap.value(fromToken.isETH() ? amount : 0)(
fromToken,
destToken,
amount,
0,
distribution,
flags
);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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
608060405234801561001057600080fd5b5060405162005276380380620052768339818101604052602081101561003557600080fd5b5051600080546001600160a01b039092166001600160a01b031990921691909117905561520e80620000686000396000f3fe60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed9514610289575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102ba565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102dd565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610277600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561020457600080fd5b82018360208201111561021657600080fd5b803590602001918460208302840111600160201b8311171561023757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610434915050565b60408051918252519081900360200190f35b34801561029557600080fd5b5061029e61080d565b604080516001600160a01b039092168252519081900360200190f35b600060606102cd878787878760006102dd565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035057600080fd5b505afa158015610364573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038d57600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156103b757600080fd5b9083019060208201858111156103cc57600080fd5b82518660208202830111600160201b821117156103e857600080fd5b82525081516020918201928201910280838360005b838110156104155781810151838201526020016103fd565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b03161415610457575083610803565b61045f61503a565b60405180610440016040528061081c8152602001610aa88152602001610af58152602001610e3b8152602001611104815260200161129a815260200161147681526020016116a681526020016118e08152602001611b1a8152602001611dc38152602001611feb81526020016123478152602001612560815260200161256c815260200161258781526020016125a281526020016125bd81526020016127f781526020016129848152602001612b788152602001612c248152602001612cfb8152602001612d9a8152602001612f8e8152602001612f9c8152602001612faa8152602001612fb88152602001612fd58152602001612feb815260200161300b8152602001613021815260200161303b81526020016130db81525090506022845111156105bc5760405162461bcd60e51b81526004018080602001828103825260428152602001806151986042913960600191505060405180910390fd5b600080805b865181101561061a5760008782815181106105d857fe5b602002602001015111156106125761060c8782815181106105f557fe5b60200260200101518461314990919063ffffffff16565b92508091505b6001016105c1565b508161067a576106328a6001600160a01b03166131ac565b1561066f5760405133903480156108fc02916000818181858888f19350505050158015610663573d6000803e3d6000fd5b50349350505050610803565b879350505050610803565b6106956001600160a01b038b1633308b63ffffffff6131e516565b60006106b06001600160a01b038c163063ffffffff6132f716565b905060005b8751811015610753578781815181106106ca57fe5b6020026020010151600014156106df5761074b565b60006107178561070b8b85815181106106f457fe5b60200260200101518e6133a190919063ffffffff16565b9063ffffffff6133fa16565b9050838214156107245750815b80830392506107498d8d838b8a876022811061073c57fe5b602002015163ffffffff16565b505b6001016106b5565b5061076d6001600160a01b038b163063ffffffff6132f716565b9450878510156107ae5760405162461bcd60e51b81526004018080602001828103825260268152602001806151126026913960400191505060405180910390fd5b6107c86001600160a01b038b16338763ffffffff61343c16565b506107fd336107e66001600160a01b038e163063ffffffff6132f716565b6001600160a01b038e16919063ffffffff61343c16565b50505050505b9695505050505050565b6000546001600160a01b031681565b8161082f6001600160a01b0386166131ac565b61096f57604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561089157600080fd5b505afa1580156108a5573d6000803e3d6000fd5b505050506040513d60208110156108bb57600080fd5b505190506001600160a01b0381161561096d576108e86001600160a01b038716828463ffffffff6134ba16565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561093e57600080fd5b505af1158015610952573d6000803e3d6000fd5b505050506040513d602081101561096857600080fd5b505191505b505b610981846001600160a01b03166131ac565b610aa157604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109e357600080fd5b505afa1580156109f7573d6000803e3d6000fd5b505050506040513d6020811015610a0d57600080fd5b505190506001600160a01b03811615610a9f57806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a6f57600080fd5b505af1158015610a83573d6000803e3d6000fd5b50505050506040513d6020811015610a9a57600080fd5b505191505b505b5050505050565b6040805162461bcd60e51b815260206004820152601a60248201527f5468697320736f75726365207761732064657072656361746564000000000000604482015290519081900360640190fd5b60007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610b5f57600080fd5b505afa158015610b73573d6000803e3d6000fd5b505050506040513d6020811015610b8957600080fd5b505190506060736f0cd8c4f6f06eab664c7e3031909452b4b728616375e1cc82610bbb6001600160a01b0389166131ac565b610bc55787610bdb565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b610bed886001600160a01b03166131ac565b610bf75787610c0d565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060006040518083038186803b158015610c6c57600080fd5b505afa158015610c80573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610ca957600080fd5b8101908080516040519392919084600160201b821115610cc857600080fd5b908301906020820185811115610cdd57600080fd5b82518660208202830111600160201b82111715610cf957600080fd5b82525081516020918201928201910280838360005b83811015610d26578181015183820152602001610d0e565b505050509050016040525050509050610d538285886001600160a01b03166134ba9092919063ffffffff16565b816001600160a01b031663f3898a97610d74886001600160a01b03166131ac565b610d7f576000610d81565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610de0578181015183820152602001610dc8565b505050509050019450505050506020604051808303818588803b158015610e0657600080fd5b505af1158015610e1a573d6000803e3d6000fd5b50505050506040513d6020811015610e3157600080fd5b5050505050505050565b610e4d846001600160a01b03166131ac565b15610eb5576000805160206150668339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e9b57600080fd5b505af1158015610eaf573d6000803e3d6000fd5b50505050505b6000610ec9856001600160a01b03166131ac565b610ed35784610ee3565b6000805160206150668339815191525b9050610f136001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff6134ba16565b73794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610f3f6001600160a01b0388166131ac565b610f495786610f59565b6000805160206150668339815191525b85610f6c886001600160a01b03166131ac565b610f765787610f86565b6000805160206150668339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610fe457600080fd5b505af1158015610ff8573d6000803e3d6000fd5b505050506040513d602081101561100e57600080fd5b5061102390506001600160a01b0385166131ac565b15610aa157604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561107b57600080fd5b505afa15801561108f573d6000803e3d6000fd5b505050506040513d60208110156110a557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156110e557600080fd5b505af11580156110f9573d6000803e3d6000fd5b505050505050505050565b60006001600160a01b0385166000805160206150f28339815191521461112b57600061112e565b60025b6001600160a01b03861660008051602061508683398151915214611153576000611156565b60015b0160ff16905060006000805160206150f28339815191526001600160a01b03861614611183576000611186565b60025b6001600160a01b038616600080516020615086833981519152146111ab5760006111ae565b60015b0160ff16905081600f0b600014806111c9575080600f0b6000145b156111d5575050611294565b6112036001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b505af115801561128d573d6000803e3d6000fd5b5050505050505b50505050565b60006001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7146112c75760006112ca565b60035b6001600160a01b0386166000805160206150f2833981519152146112ef5760006112f2565b60025b6001600160a01b0387166000805160206150868339815191521461131757600061131a565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b03161461135757600061135a565b60035b6001600160a01b0386166000805160206150f28339815191521461137f576000611382565b60025b6001600160a01b038716600080516020615086833981519152146113a75760006113aa565b60015b010160ff16905081600f0b600014806113c6575080600f0b6000145b156113d2575050611294565b6114006001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b0385166e085d4780b73119b644ae5ecd22b3761461149e5760006114a1565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146114cc5760006114cf565b60035b6001600160a01b0387166000805160206150f2833981519152146114f45760006114f7565b60025b6001600160a01b0388166000805160206150868339815191521461151c57600061151f565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b03161461155857600061155b565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611586576000611589565b60035b6001600160a01b0387166000805160206150f2833981519152146115ae5760006115b1565b60025b6001600160a01b038816600080516020615086833981519152146115d65760006115d9565b60015b01010160ff16905081600f0b600014806115f6575080600f0b6000145b15611602575050611294565b6116306001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c53146116d35760006116d6565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611701576000611704565b60035b6001600160a01b0387166000805160206150f28339815191521461172957600061172c565b60025b6001600160a01b03881660008051602061508683398151915214611751576000611754565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b031614611792576000611795565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146117c05760006117c3565b60035b6001600160a01b0387166000805160206150f2833981519152146117e85760006117eb565b60025b6001600160a01b03881660008051602061508683398151915214611810576000611813565b60015b01010160ff16905081600f0b60001480611830575080600f0b6000145b1561183c575050611294565b61186a6001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f511461190d576000611910565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461193b57600061193e565b60035b6001600160a01b0387166000805160206150f283398151915214611963576000611966565b60025b6001600160a01b0388166000805160206150868339815191521461198b57600061198e565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b0316146119cc5760006119cf565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146119fa5760006119fd565b60035b6001600160a01b0387166000805160206150f283398151915214611a22576000611a25565b60025b6001600160a01b03881660008051602061508683398151915214611a4a576000611a4d565b60015b01010160ff16905081600f0b60001480611a6a575080600f0b6000145b15611a76575050611294565b611aa46001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b611b2c846001600160a01b03166131ac565b611c7357604080516332a5d5bf60e01b81526001600160a01b0386166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611b8e57600080fd5b505afa158015611ba2573d6000803e3d6000fd5b505050506040513d6020811015611bb857600080fd5b50519050611bd66001600160a01b038616828563ffffffff6134ba16565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d6020811015611c4657600080fd5b50611c6d90508185611c676001600160a01b0383163063ffffffff6132f716565b8561081c565b50611294565b611c85836001600160a01b03166131ac565b61129457604080516332a5d5bf60e01b81526001600160a01b0385166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611ce757600080fd5b505afa158015611cfb573d6000803e3d6000fd5b505050506040513d6020811015611d1157600080fd5b50519050611d218582858561081c565b6001600160a01b03811663db006a75611d40823063ffffffff6132f716565b6040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611d7657600080fd5b505af1158015611d8a573d6000803e3d6000fd5b505050506040513d6020811015611da057600080fd5b50611dbc90506001600160a01b0385163063ffffffff6132f716565b5050611294565b6001600160a01b0384166000805160206150868339815191521415611eb857611e106001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff6134ba16565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611e6957600080fd5b505af1158015611e7d573d6000803e3d6000fd5b50611eb392507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611ead823063ffffffff6132f716565b8461081c565b611294565b6001600160a01b038316600080516020615086833981519152141561129457611ef7847306af07097c9eeb7fd685c692751d5c66db49c215848461081c565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c2159263ef693bed92909184916370a08231916024808301926020929190829003018186803b158015611f5457600080fd5b505afa158015611f68573d6000803e3d6000fd5b505050506040513d6020811015611f7e57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015611fce57600080fd5b505af1158015611fe2573d6000803e3d6000fd5b50505050611294565b611ffd846001600160a01b03166131ac565b6121c35760408051635f5418f360e01b81526001600160a01b0386166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561205f57600080fd5b505afa158015612073573d6000803e3d6000fd5b505050506040513d602081101561208957600080fd5b50516040805163797a759360e11b815290519192506121209173398ec7346dcd622edc5ae82352f02be94c62d1199163f2f4eb26916004808301926020929190829003018186803b1580156120dd57600080fd5b505afa1580156120f1573d6000803e3d6000fd5b505050506040513d602081101561210757600080fd5b50516001600160a01b038716908563ffffffff6134ba16565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b15801561218a57600080fd5b505af115801561219e573d6000803e3d6000fd5b50505050611c6d8185611c6730856001600160a01b03166132f790919063ffffffff16565b6121d5836001600160a01b03166131ac565b6112945760408051635f5418f360e01b81526001600160a01b0385166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561223757600080fd5b505afa15801561224b573d6000803e3d6000fd5b505050506040513d602081101561226157600080fd5b505190506122718582858561081c565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163db006a759183916370a08231916024808301926020929190829003018186803b1580156122bf57600080fd5b505afa1580156122d3573d6000803e3d6000fd5b505050506040513d60208110156122e957600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561232957600080fd5b505af115801561233d573d6000803e3d6000fd5b5050505050611294565b60007371cd6666064c3a1354a3b4dca5fa1e2d3ee7d30363901754d76123756001600160a01b0388166131ac565b61237f5786612382565b60005b612394876001600160a01b03166131ac565b61239e57866123a1565b60005b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b15801561240057600080fd5b505afa158015612414573d6000803e3d6000fd5b505050506040513d602081101561242a57600080fd5b505190506124486001600160a01b038616828563ffffffff6134ba16565b806001600160a01b031663d5bcb9b5612469876001600160a01b03166131ac565b612474576000612476565b845b612488886001600160a01b03166131ac565b6124925787612495565b60005b6124a7886001600160a01b03166131ac565b6124b157876124b4565b60005b604080516001600160e01b031960e087901b1681526001600160a01b03938416600482015291909216602482015260448101889052600060648201527368a17b587caf4f9329f0e372e3a78d23a46de6b56084820152905160a480830192602092919082900301818588803b15801561252c57600080fd5b505af1158015612540573d6000803e3d6000fd5b50505050506040513d602081101561255757600080fd5b50505050505050565b610aa1848484846135b3565b61129484600080516020615066833981519152858585613a47565b61129484600080516020615086833981519152858585613a47565b611294846000805160206150f2833981519152858585613a47565b60006001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e1146125ea5760006125ed565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461261857600061261b565b60035b6001600160a01b0387166000805160206150f283398151915214612640576000612643565b60025b6001600160a01b0388166000805160206150868339815191521461266857600061266b565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146126a95760006126ac565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146126d75760006126da565b60035b6001600160a01b0387166000805160206150f2833981519152146126ff576000612702565b60025b6001600160a01b0388166000805160206150868339815191521461272757600061272a565b60015b01010160ff16905081600f0b60001480612747575080600f0b6000145b15612753575050611294565b6127816001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c59914612824576000612827565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612852576000612855565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b0386161461288857600061288b565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146128b65760006128b9565b60015b0160ff16905081600f0b600014806128d4575080600f0b6000145b156128e0575050611294565b61290e6001600160a01b0387167393054188d876f558f4a66b2ef1d97d16edf0895b8663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517393054188d876f558f4a66b2ef1d97d16edf0895b92633df02124926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146129b15760006129b4565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c599146129df5760006129e2565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612a0d576000612a10565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612a4d576000612a50565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612a7b576000612a7e565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612aa9576000612aac565b60015b010160ff16905081600f0b60001480612ac8575080600f0b6000145b15612ad4575050611294565b612b026001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561127957600080fd5b612ba66001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff6134ba16565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b158015612c1057600080fd5b505af1158015610e31573d6000803e3d6000fd5b612c526001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff6134ba16565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b158015612cd157600080fd5b505af1158015612ce5573d6000803e3d6000fd5b505050506040513d6020811015610a9f57600080fd5b612d296001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff6134ba16565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015612cd157600080fd5b60006001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612dc7576000612dca565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612df5576000612df8565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612e23576000612e26565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612e63576000612e66565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612e91576000612e94565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612ebf576000612ec2565b60015b010160ff16905081600f0b60001480612ede575080600f0b6000145b15612eea575050611294565b612f186001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561127957600080fd5b611294848484846000613a5e565b611294848484846001613a5e565b611294848484846002613a5e565b611294848484846001685a434ecd46efdcc7c760b11b0319613ecf565b61129484848484600161543360e81b0319613ecf565b6112948484848460016b2c2466af65a2f7eba2a7a463609a1b0319613ecf565b6112948484848461301c89896146ff565b613ecf565b61302e8460008484612347565b6112946000844784612347565b613055846000805160206150868339815191528484612347565b604080516370a0823160e01b815230600482015290516112949160008051602061508683398151915291869183916370a0823191602480820192602092909190829003018186803b1580156130a957600080fd5b505afa1580156130bd573d6000803e3d6000fd5b505050506040513d60208110156130d357600080fd5b505184612347565b6130f5846000805160206150f28339815191528484612347565b604080516370a0823160e01b81523060048201529051611294916000805160206150f283398151915291869183916370a0823191602480820192602092909190829003018186803b1580156130a957600080fd5b6000828201838110156131a3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b03821615806131a657506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b806131ef57611294565b6131f8846131ac565b156132dc576001600160a01b038316331480156132155750803410155b6132505760405162461bcd60e51b815260040180806020018281038252602b8152602001806150a6602b913960400191505060405180910390fd5b6001600160a01b0382163014613298576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613296573d6000803e3d6000fd5b505b80341115611eb357336108fc6132b4348463ffffffff61497a16565b6040518115909202916000818181858888f19350505050158015611c6d573d6000803e3d6000fd5b6112946001600160a01b03851684848463ffffffff6149bc16565b6000613302836131ac565b1561331857506001600160a01b038116316131a6565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561336e57600080fd5b505afa158015613382573d6000803e3d6000fd5b505050506040513d602081101561339857600080fd5b505190506131a6565b6000826133b0575060006131a6565b828202828482816133bd57fe5b04146131a35760405162461bcd60e51b81526004018080602001828103825260218152602001806150d16021913960400191505060405180910390fd5b60006131a383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614a16565b60008161344b575060016134b3565b613454846131ac565b15613495576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561348f573d6000803e3d6000fd5b506134b3565b6134af6001600160a01b038516848463ffffffff614ab816565b5060015b9392505050565b6134c3836131ac565b6135ae57806134ec576134e76001600160a01b03841683600063ffffffff614b0a16565b6135ae565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561353d57600080fd5b505afa158015613551573d6000803e3d6000fd5b505050506040513d602081101561356757600080fd5b5051905081811015611294578015613594576135946001600160a01b03851684600063ffffffff614b0a16565b6112946001600160a01b038516848463ffffffff614b0a16565b505050565b60006135c7856001600160a01b03166131ac565b1561362f576000805160206150668339815191526001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561361557600080fd5b505af1158015613629573d6000803e3d6000fd5b50505050505b6000613643866001600160a01b03166131ac565b61364d578561365d565b6000805160206150668339815191525b90506000613673866001600160a01b03166131ac565b61367d578561368d565b6000805160206150668339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b1580156136f557600080fd5b505afa158015613709573d6000803e3d6000fd5b505050506040513d602081101561371f57600080fd5b505190506000806137416001600160a01b03841686868b63ffffffff614c1d16565b9197509250905081156137a657826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561378957600080fd5b505af115801561379d573d6000803e3d6000fd5b50505050613820565b8015613820576040805163bc25cf7760e01b81527368a17b587caf4f9329f0e372e3a78d23a46de6b5600482015290516001600160a01b0385169163bc25cf7791602480830192600092919082900301818387803b15801561380757600080fd5b505af115801561381b573d6000803e3d6000fd5b505050505b61383a6001600160a01b038616848a63ffffffff61343c16565b50836001600160a01b0316856001600160a01b031610156138d3576040805163022c0d9f60e01b815260006004820181905260248201899052306044830152608060648301526084820181905291516001600160a01b0386169263022c0d9f9260c4808201939182900301818387803b1580156138b657600080fd5b505af11580156138ca573d6000803e3d6000fd5b5050505061394d565b6040805163022c0d9f60e01b815260048101889052600060248201819052306044830152608060648301526084820181905291516001600160a01b0386169263022c0d9f9260c4808201939182900301818387803b15801561393457600080fd5b505af1158015613948573d6000803e3d6000fd5b505050505b61395f896001600160a01b03166131ac565b15613a3a57604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156139b757600080fd5b505afa1580156139cb573d6000803e3d6000fd5b505050506040513d60208110156139e157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015613a2157600080fd5b505af1158015613a35573d6000803e3d6000fd5b505050505b5050505050949350505050565b610a9f8484613a58888887876135b3565b846135b3565b60607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc43613a8c6001600160a01b0389166131ac565b613a965787613aa6565b6000805160206150668339815191525b613ab8886001600160a01b03166131ac565b613ac25787613ad2565b6000805160206150668339815191525b856001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b158015613b3c57600080fd5b505afa158015613b50573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015613b7957600080fd5b8101908080516040519392919084600160201b821115613b9857600080fd5b908301906020820185811115613bad57600080fd5b82518660208202830111600160201b82111715613bc957600080fd5b82525081516020918201928201910280838360005b83811015613bf6578181015183820152602001613bde565b505050509050016040525050509050613c17866001600160a01b03166131ac565b15613c7f576000805160206150668339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c6557600080fd5b505af1158015613c79573d6000803e3d6000fd5b50505050505b613cd9818381518110613c8e57fe5b602002602001015185613ca9896001600160a01b03166131ac565b613cb35788613cc3565b6000805160206150668339815191525b6001600160a01b0316919063ffffffff6134ba16565b808281518110613ce557fe5b60200260200101516001600160a01b0316638201aa3f613d0d886001600160a01b03166131ac565b613d175787613d27565b6000805160206150668339815191525b86613d3a896001600160a01b03166131ac565b613d445788613d54565b6000805160206150668339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b158015613dce57600080fd5b505af1158015613de2573d6000803e3d6000fd5b505050506040513d6040811015613df857600080fd5b50613e0d90506001600160a01b0386166131ac565b15610a9f57604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613e6557600080fd5b505afa158015613e79573d6000803e3d6000fd5b505050506040513d6020811015613e8f57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561127957600080fd5b604080516001808252818301909252849160609190602080830190803883390190505090508281600081518110613f0257fe5b602002602001018181525050613f20876001600160a01b03166131ac565b61432157606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166361e597f9896001856000604051908082528060200260200182016040528015613f78578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001846003811115613fb057fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015613ff8578181015183820152602001613fe0565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561403757818101518382015260200161401f565b50505050905001965050505050505060006040518083038186803b15801561405e57600080fd5b505afa158015614072573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561409b57600080fd5b8101908080516040519392919084600160201b8211156140ba57600080fd5b9083019060208201858111156140cf57600080fd5b8251600160201b8111828201881017156140e857600080fd5b82525081516020918201929091019080838360005b838110156141155781810151838201526020016140fd565b50505050905090810190601f1680156141425780820380516001836020036101000a031916815260200191505b506040525091925061417b9150506001600160a01b038916739aab3f75489902f3a48495025729a0af77d4b11e8863ffffffff6134ba16565b739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d54898573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3060001960007368a17b587caf4f9329f0e372e3a78d23a46de6b560ff8e901c600a028a6040518a63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561429d578181015183820152602001614285565b50505050905090810190601f1680156142ca5780820380516001836020036101000a031916815260200191505b509a5050505050505050505050602060405180830381600087803b1580156142f157600080fd5b505af1158015614305573d6000803e3d6000fd5b505050506040513d602081101561431b57600080fd5b50519250505b614333866001600160a01b03166131ac565b61255757606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166381efcbdd88600185600060405190808252806020026020018201604052801561438b578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b031681526020018460038111156143c357fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561440b5781810151838201526020016143f3565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561444a578181015183820152602001614432565b50505050905001965050505050505060006040518083038186803b15801561447157600080fd5b505afa158015614485573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156144ae57600080fd5b8101908080516040519392919084600160201b8211156144cd57600080fd5b9083019060208201858111156144e257600080fd5b8251600160201b8111828201881017156144fb57600080fd5b82525081516020918201929091019080838360005b83811015614528578181015183820152602001614510565b50505050905090810190601f1680156145555780820380516001836020036101000a031916815260200191505b506040525050509050739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868b3060001960007368a17b587caf4f9329f0e372e3a78d23a46de6b560ff8f901c600a028b6040518b63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614681578181015183820152602001614669565b50505050905090810190601f1680156146ae5780820380516001836020036101000a031916815260200191505b509a50505050505050505050506020604051808303818588803b1580156146d457600080fd5b505af11580156146e8573d6000803e3d6000fd5b50505050506040513d602081101561128d57600080fd5b6000614713836001600160a01b03166131ac565b15801561472f575061472d826001600160a01b03166131ac565b155b1561473c575060006131a6565b606073c8fb12402cb16970f3c5f4b48ff68eb9d1289301633d3dc52c61476a6001600160a01b0387166131ac565b6147745785614776565b845b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060006040518083038186803b1580156147bc57600080fd5b505afa1580156147d0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156147f957600080fd5b8101908080516040519392919084600160201b82111561481857600080fd5b90830190602082018581111561482d57600080fd5b82518660208202830111600160201b8211171561484957600080fd5b82525081516020918201928201910280838360005b8381101561487657818101518382015260200161485e565b50505050905001604052505050905060008090505b815181101561496f5760f88282815181106148a257fe5b602002602001015160001c901c60bb141580156148e557508181815181106148c657fe5b60200260200101516001685a434ecd46efdcc7c760b11b031960001b14155b801561491057508181815181106148f857fe5b6020026020010151600161543360e81b031960001b14155b8015614945575081818151811061492357fe5b602002602001015160016b2c2466af65a2f7eba2a7a463609a1b031960001b14155b156149675781818151811061495657fe5b6020026020010151925050506131a6565b60010161488b565b506000949350505050565b60006131a383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614dd6565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611294908590614e30565b60008183614aa25760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614a67578181015183820152602001614a4f565b50505050905090810190601f168015614a945780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581614aae57fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526135ae908490614e30565b801580614b90575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015614b6257600080fd5b505afa158015614b76573d6000803e3d6000fd5b505050506040513d6020811015614b8c57600080fd5b5051155b614bcb5760405162461bcd60e51b81526004018080602001828103825260368152602001806151626036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526135ae908490614e30565b6000808080614c3b6001600160a01b0388168963ffffffff6132f716565b90506000614c586001600160a01b0388168a63ffffffff6132f716565b90506000808a6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015614c9657600080fd5b505afa158015614caa573d6000803e3d6000fd5b505050506040513d6060811015614cc057600080fd5b50805160209091015190925090506001600160a01b03808a16908b161115614ce457905b816001600160701b0316841080614d035750806001600160701b031683105b955085158015614d2d5750816001600160701b0316841180614d2d5750806001600160701b031683115b94506000614d43896103e563ffffffff6133a116565b90506000614d6a614d5d86856001600160701b0316614fe8565b839063ffffffff6133a116565b90506000614da383614d976103e8614d8b8b8a6001600160701b0316614fe8565b9063ffffffff6133a116565b9063ffffffff61314916565b90508015614dc057614dbb828263ffffffff6133fa16565b614dc3565b60005b9950505050505050509450945094915050565b60008184841115614e285760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614a67578181015183820152602001614a4f565b505050900390565b614e42826001600160a01b0316614ffe565b614e93576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614ed15780518252601f199092019160209182019101614eb2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614f33576040519150601f19603f3d011682016040523d82523d6000602084013e614f38565b606091505b509150915081614f8f576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561129457808060200190516020811015614fab57600080fd5b50516112945760405162461bcd60e51b815260040180806020018281038252602a815260200180615138602a913960400191505060405180910390fd5b6000818310614ff757816131a3565b5090919050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061503257508115155b949350505050565b6040518061044001604052806022905b61506381526020019060019003908161504a5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a72315820a7810b563a2b3b8d2c6de6f3026721a61f47df98505f5574f26361201e0559cf64736f6c634300051100320000000000000000000000001a3f7583c0af24ef78cdb1a1eb48d957df793824
Deployed Bytecode
0x60806040526004361061003f5760003560e01c8063085e2c5b1461004e5780638373f265146100f8578063e2a7515e146101af578063fbe4ed9514610289575b3332141561004c57600080fd5b005b34801561005a57600080fd5b5061009d600480360360a081101561007157600080fd5b506001600160a01b038135811691602081013590911690604081013590606081013590608001356102ba565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156100e35781810151838201526020016100cb565b50505050905001935050505060405180910390f35b34801561010457600080fd5b5061014d600480360360c081101561011b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a001356102dd565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610199578181015183820152602001610181565b5050505090500194505050505060405180910390f35b610277600480360360c08110156101c557600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561020457600080fd5b82018360208201111561021657600080fd5b803590602001918460208302840111600160201b8311171561023757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610434915050565b60408051918252519081900360200190f35b34801561029557600080fd5b5061029e61080d565b604080516001600160a01b039092168252519081900360200190f35b600060606102cd878787878760006102dd565b9199919850909650505050505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b15801561035057600080fd5b505afa158015610364573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561038d57600080fd5b81516020830151604080850180519151939592948301929184600160201b8211156103b757600080fd5b9083019060208201858111156103cc57600080fd5b82518660208202830111600160201b821117156103e857600080fd5b82525081516020918201928201910280838360005b838110156104155781810151838201526020016103fd565b5050505090500160405250505092509250925096509650969350505050565b6000856001600160a01b0316876001600160a01b03161415610457575083610803565b61045f61503a565b60405180610440016040528061081c8152602001610aa88152602001610af58152602001610e3b8152602001611104815260200161129a815260200161147681526020016116a681526020016118e08152602001611b1a8152602001611dc38152602001611feb81526020016123478152602001612560815260200161256c815260200161258781526020016125a281526020016125bd81526020016127f781526020016129848152602001612b788152602001612c248152602001612cfb8152602001612d9a8152602001612f8e8152602001612f9c8152602001612faa8152602001612fb88152602001612fd58152602001612feb815260200161300b8152602001613021815260200161303b81526020016130db81525090506022845111156105bc5760405162461bcd60e51b81526004018080602001828103825260428152602001806151986042913960600191505060405180910390fd5b600080805b865181101561061a5760008782815181106105d857fe5b602002602001015111156106125761060c8782815181106105f557fe5b60200260200101518461314990919063ffffffff16565b92508091505b6001016105c1565b508161067a576106328a6001600160a01b03166131ac565b1561066f5760405133903480156108fc02916000818181858888f19350505050158015610663573d6000803e3d6000fd5b50349350505050610803565b879350505050610803565b6106956001600160a01b038b1633308b63ffffffff6131e516565b60006106b06001600160a01b038c163063ffffffff6132f716565b905060005b8751811015610753578781815181106106ca57fe5b6020026020010151600014156106df5761074b565b60006107178561070b8b85815181106106f457fe5b60200260200101518e6133a190919063ffffffff16565b9063ffffffff6133fa16565b9050838214156107245750815b80830392506107498d8d838b8a876022811061073c57fe5b602002015163ffffffff16565b505b6001016106b5565b5061076d6001600160a01b038b163063ffffffff6132f716565b9450878510156107ae5760405162461bcd60e51b81526004018080602001828103825260268152602001806151126026913960400191505060405180910390fd5b6107c86001600160a01b038b16338763ffffffff61343c16565b506107fd336107e66001600160a01b038e163063ffffffff6132f716565b6001600160a01b038e16919063ffffffff61343c16565b50505050505b9695505050505050565b6000546001600160a01b031681565b8161082f6001600160a01b0386166131ac565b61096f57604080516303795fb160e11b81526001600160a01b0387166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b15801561089157600080fd5b505afa1580156108a5573d6000803e3d6000fd5b505050506040513d60208110156108bb57600080fd5b505190506001600160a01b0381161561096d576108e86001600160a01b038716828463ffffffff6134ba16565b604080516395e3c50b60e01b8152600481018490526001602482015242604482015290516001600160a01b038316916395e3c50b9160648083019260209291908290030181600087803b15801561093e57600080fd5b505af1158015610952573d6000803e3d6000fd5b505050506040513d602081101561096857600080fd5b505191505b505b610981846001600160a01b03166131ac565b610aa157604080516303795fb160e11b81526001600160a01b0386166004820152905160009173c0a47dfe034b400b47bdad5fecda2621de6c4d95916306f2bf6291602480820192602092909190829003018186803b1580156109e357600080fd5b505afa1580156109f7573d6000803e3d6000fd5b505050506040513d6020811015610a0d57600080fd5b505190506001600160a01b03811615610a9f57806001600160a01b031663f39b5b9b836001426040518463ffffffff1660e01b815260040180838152602001828152602001925050506020604051808303818588803b158015610a6f57600080fd5b505af1158015610a83573d6000803e3d6000fd5b50505050506040513d6020811015610a9a57600080fd5b505191505b505b5050505050565b6040805162461bcd60e51b815260206004820152601a60248201527f5468697320736f75726365207761732064657072656361746564000000000000604482015290519081900360640190fd5b60007352ae12abe5d8bd778bd5397f99ca900624cfadd46001600160a01b031663bb34534c6040518163ffffffff1660e01b815260040180806c42616e636f724e6574776f726b60981b815250602001905060206040518083038186803b158015610b5f57600080fd5b505afa158015610b73573d6000803e3d6000fd5b505050506040513d6020811015610b8957600080fd5b505190506060736f0cd8c4f6f06eab664c7e3031909452b4b728616375e1cc82610bbb6001600160a01b0389166131ac565b610bc55787610bdb565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b610bed886001600160a01b03166131ac565b610bf75787610c0d565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3155b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060006040518083038186803b158015610c6c57600080fd5b505afa158015610c80573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610ca957600080fd5b8101908080516040519392919084600160201b821115610cc857600080fd5b908301906020820185811115610cdd57600080fd5b82518660208202830111600160201b82111715610cf957600080fd5b82525081516020918201928201910280838360005b83811015610d26578181015183820152602001610d0e565b505050509050016040525050509050610d538285886001600160a01b03166134ba9092919063ffffffff16565b816001600160a01b031663f3898a97610d74886001600160a01b03166131ac565b610d7f576000610d81565b855b838760016040518563ffffffff1660e01b81526004018080602001848152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015610de0578181015183820152602001610dc8565b505050509050019450505050506020604051808303818588803b158015610e0657600080fd5b505af1158015610e1a573d6000803e3d6000fd5b50505050506040513d6020811015610e3157600080fd5b5050505050505050565b610e4d846001600160a01b03166131ac565b15610eb5576000805160206150668339815191526001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e9b57600080fd5b505af1158015610eaf573d6000803e3d6000fd5b50505050505b6000610ec9856001600160a01b03166131ac565b610ed35784610ee3565b6000805160206150668339815191525b9050610f136001600160a01b03821673794e6e91555438afc3ccf1c5076a74f42133d08d8563ffffffff6134ba16565b73794e6e91555438afc3ccf1c5076a74f42133d08d630621b4f6610f3f6001600160a01b0388166131ac565b610f495786610f59565b6000805160206150668339815191525b85610f6c886001600160a01b03166131ac565b610f765787610f86565b6000805160206150668339815191525b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260016064820152905160848083019260209291908290030181600087803b158015610fe457600080fd5b505af1158015610ff8573d6000803e3d6000fd5b505050506040513d602081101561100e57600080fd5b5061102390506001600160a01b0385166131ac565b15610aa157604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b15801561107b57600080fd5b505afa15801561108f573d6000803e3d6000fd5b505050506040513d60208110156110a557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b1580156110e557600080fd5b505af11580156110f9573d6000803e3d6000fd5b505050505050505050565b60006001600160a01b0385166000805160206150f28339815191521461112b57600061112e565b60025b6001600160a01b03861660008051602061508683398151915214611153576000611156565b60015b0160ff16905060006000805160206150f28339815191526001600160a01b03861614611183576000611186565b60025b6001600160a01b038616600080516020615086833981519152146111ab5760006111ae565b60015b0160ff16905081600f0b600014806111c9575080600f0b6000145b156111d5575050611294565b6112036001600160a01b03871673a2b47e3d5c44877cca798226b7b8118f9bfb7a568663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a2b47e3d5c44877cca798226b7b8118f9bfb7a569263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b505af115801561128d573d6000803e3d6000fd5b5050505050505b50505050565b60006001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7146112c75760006112ca565b60035b6001600160a01b0386166000805160206150f2833981519152146112ef5760006112f2565b60025b6001600160a01b0387166000805160206150868339815191521461131757600061131a565b60015b010160ff169050600073dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316856001600160a01b03161461135757600061135a565b60035b6001600160a01b0386166000805160206150f28339815191521461137f576000611382565b60025b6001600160a01b038716600080516020615086833981519152146113a75760006113aa565b60015b010160ff16905081600f0b600014806113c6575080600f0b6000145b156113d2575050611294565b6114006001600160a01b0387167352ea46506b9cc5ef470c5bf89f17dc28bb35d85c8663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517352ea46506b9cc5ef470c5bf89f17dc28bb35d85c9263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b0385166e085d4780b73119b644ae5ecd22b3761461149e5760006114a1565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146114cc5760006114cf565b60035b6001600160a01b0387166000805160206150f2833981519152146114f45760006114f7565b60025b6001600160a01b0388166000805160206150868339815191521461151c57600061151f565b60015b01010160ff16905060006e085d4780b73119b644ae5ecd22b3766001600160a01b0316856001600160a01b03161461155857600061155b565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611586576000611589565b60035b6001600160a01b0387166000805160206150f2833981519152146115ae5760006115b1565b60025b6001600160a01b038816600080516020615086833981519152146115d65760006115d9565b60015b01010160ff16905081600f0b600014806115f6575080600f0b6000145b15611602575050611294565b6116306001600160a01b0387167345f783cce6b7ff23b2ab2d70e416cdb7d6055f518663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517345f783cce6b7ff23b2ab2d70e416cdb7d6055f519263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516734fabb145d64652a948d72533023f6e7a623c7c53146116d35760006116d6565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec714611701576000611704565b60035b6001600160a01b0387166000805160206150f28339815191521461172957600061172c565b60025b6001600160a01b03881660008051602061508683398151915214611751576000611754565b60015b01010160ff1690506000734fabb145d64652a948d72533023f6e7a623c7c536001600160a01b0316856001600160a01b031614611792576000611795565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146117c05760006117c3565b60035b6001600160a01b0387166000805160206150f2833981519152146117e85760006117eb565b60025b6001600160a01b03881660008051602061508683398151915214611810576000611813565b60015b01010160ff16905081600f0b60001480611830575080600f0b6000145b1561183c575050611294565b61186a6001600160a01b0387167379a8c46dea5ada233abaffd40f3a0a2b1e5a4f278663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517379a8c46dea5ada233abaffd40f3a0a2b1e5a4f279263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b0385167357ab1ec28d129707052df4df418d58a2d46d5f511461190d576000611910565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461193b57600061193e565b60035b6001600160a01b0387166000805160206150f283398151915214611963576000611966565b60025b6001600160a01b0388166000805160206150868339815191521461198b57600061198e565b60015b01010160ff16905060007357ab1ec28d129707052df4df418d58a2d46d5f516001600160a01b0316856001600160a01b0316146119cc5760006119cf565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146119fa5760006119fd565b60035b6001600160a01b0387166000805160206150f283398151915214611a22576000611a25565b60025b6001600160a01b03881660008051602061508683398151915214611a4a576000611a4d565b60015b01010160ff16905081600f0b60001480611a6a575080600f0b6000145b15611a76575050611294565b611aa46001600160a01b03871673a5407eae9ba41422680e2e00537571bcc53efbfd8663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b602482015260448101869052600060648201819052915173a5407eae9ba41422680e2e00537571bcc53efbfd9263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b611b2c846001600160a01b03166131ac565b611c7357604080516332a5d5bf60e01b81526001600160a01b0386166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611b8e57600080fd5b505afa158015611ba2573d6000803e3d6000fd5b505050506040513d6020811015611bb857600080fd5b50519050611bd66001600160a01b038616828563ffffffff6134ba16565b806001600160a01b031663a0712d68846040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611c1c57600080fd5b505af1158015611c30573d6000803e3d6000fd5b505050506040513d6020811015611c4657600080fd5b50611c6d90508185611c676001600160a01b0383163063ffffffff6132f716565b8561081c565b50611294565b611c85836001600160a01b03166131ac565b61129457604080516332a5d5bf60e01b81526001600160a01b0385166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d1916332a5d5bf91602480820192602092909190829003018186803b158015611ce757600080fd5b505afa158015611cfb573d6000803e3d6000fd5b505050506040513d6020811015611d1157600080fd5b50519050611d218582858561081c565b6001600160a01b03811663db006a75611d40823063ffffffff6132f716565b6040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611d7657600080fd5b505af1158015611d8a573d6000803e3d6000fd5b505050506040513d6020811015611da057600080fd5b50611dbc90506001600160a01b0385163063ffffffff6132f716565b5050611294565b6001600160a01b0384166000805160206150868339815191521415611eb857611e106001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2158463ffffffff6134ba16565b60408051633b4da69f60e01b81523060048201526024810184905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611e6957600080fd5b505af1158015611e7d573d6000803e3d6000fd5b50611eb392507306af07097c9eeb7fd685c692751d5c66db49c2159150859050611ead823063ffffffff6132f716565b8461081c565b611294565b6001600160a01b038316600080516020615086833981519152141561129457611ef7847306af07097c9eeb7fd685c692751d5c66db49c215848461081c565b604080516370a0823160e01b8152306004820181905291517306af07097c9eeb7fd685c692751d5c66db49c2159263ef693bed92909184916370a08231916024808301926020929190829003018186803b158015611f5457600080fd5b505afa158015611f68573d6000803e3d6000fd5b505050506040513d6020811015611f7e57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b158015611fce57600080fd5b505af1158015611fe2573d6000803e3d6000fd5b50505050611294565b611ffd846001600160a01b03166131ac565b6121c35760408051635f5418f360e01b81526001600160a01b0386166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561205f57600080fd5b505afa158015612073573d6000803e3d6000fd5b505050506040513d602081101561208957600080fd5b50516040805163797a759360e11b815290519192506121209173398ec7346dcd622edc5ae82352f02be94c62d1199163f2f4eb26916004808301926020929190829003018186803b1580156120dd57600080fd5b505afa1580156120f1573d6000803e3d6000fd5b505050506040513d602081101561210757600080fd5b50516001600160a01b038716908563ffffffff6134ba16565b60408051636968703360e11b81526001600160a01b03871660048201526024810185905261044d6044820152905173398ec7346dcd622edc5ae82352f02be94c62d1199163d2d0e06691606480830192600092919082900301818387803b15801561218a57600080fd5b505af115801561219e573d6000803e3d6000fd5b50505050611c6d8185611c6730856001600160a01b03166132f790919063ffffffff16565b6121d5836001600160a01b03166131ac565b6112945760408051635f5418f360e01b81526001600160a01b0385166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c2652149491635f5418f391602480820192602092909190829003018186803b15801561223757600080fd5b505afa15801561224b573d6000803e3d6000fd5b505050506040513d602081101561226157600080fd5b505190506122718582858561081c565b604080516370a0823160e01b815230600482015290516001600160a01b0383169163db006a759183916370a08231916024808301926020929190829003018186803b1580156122bf57600080fd5b505afa1580156122d3573d6000803e3d6000fd5b505050506040513d60208110156122e957600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561232957600080fd5b505af115801561233d573d6000803e3d6000fd5b5050505050611294565b60007371cd6666064c3a1354a3b4dca5fa1e2d3ee7d30363901754d76123756001600160a01b0388166131ac565b61237f5786612382565b60005b612394876001600160a01b03166131ac565b61239e57866123a1565b60005b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b03168152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b15801561240057600080fd5b505afa158015612414573d6000803e3d6000fd5b505050506040513d602081101561242a57600080fd5b505190506124486001600160a01b038616828563ffffffff6134ba16565b806001600160a01b031663d5bcb9b5612469876001600160a01b03166131ac565b612474576000612476565b845b612488886001600160a01b03166131ac565b6124925787612495565b60005b6124a7886001600160a01b03166131ac565b6124b157876124b4565b60005b604080516001600160e01b031960e087901b1681526001600160a01b03938416600482015291909216602482015260448101889052600060648201527368a17b587caf4f9329f0e372e3a78d23a46de6b56084820152905160a480830192602092919082900301818588803b15801561252c57600080fd5b505af1158015612540573d6000803e3d6000fd5b50505050506040513d602081101561255757600080fd5b50505050505050565b610aa1848484846135b3565b61129484600080516020615066833981519152858585613a47565b61129484600080516020615086833981519152858585613a47565b611294846000805160206150f2833981519152858585613a47565b60006001600160a01b038516738e870d67f660d95d5be530380d0ec0bd388289e1146125ea5760006125ed565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec71461261857600061261b565b60035b6001600160a01b0387166000805160206150f283398151915214612640576000612643565b60025b6001600160a01b0388166000805160206150868339815191521461266857600061266b565b60015b01010160ff1690506000738e870d67f660d95d5be530380d0ec0bd388289e16001600160a01b0316856001600160a01b0316146126a95760006126ac565b60045b6001600160a01b03861673dac17f958d2ee523a2206206994597c13d831ec7146126d75760006126da565b60035b6001600160a01b0387166000805160206150f2833981519152146126ff576000612702565b60025b6001600160a01b0388166000805160206150868339815191521461272757600061272a565b60015b01010160ff16905081600f0b60001480612747575080600f0b6000145b15612753575050611294565b6127816001600160a01b0387167306364f10b501e868329afbc005b3492902d6c7638663ffffffff6134ba16565b60408051635320bf6b60e11b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517306364f10b501e868329afbc005b3492902d6c7639263a6417ed6926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516732260fac5e5542a773aa44fbcfedf7c193bc2c59914612824576000612827565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612852576000612855565b60015b0160ff1690506000732260fac5e5542a773aa44fbcfedf7c193bc2c5996001600160a01b0386161461288857600061288b565b60025b6001600160a01b03861673eb4c2781e4eba804ce9a9803c67d0893436bb27d146128b65760006128b9565b60015b0160ff16905081600f0b600014806128d4575080600f0b6000145b156128e0575050611294565b61290e6001600160a01b0387167393054188d876f558f4a66b2ef1d97d16edf0895b8663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b60248201526044810186905260006064820181905291517393054188d876f558f4a66b2ef1d97d16edf0895b92633df02124926084808201939182900301818387803b15801561127957600080fd5b60006001600160a01b038516730316eb71485b0ab14103307bf65a021042c6d380146129b15760006129b4565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c599146129df5760006129e2565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612a0d576000612a10565b60015b010160ff1690506000730316eb71485b0ab14103307bf65a021042c6d3806001600160a01b0316856001600160a01b031614612a4d576000612a50565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612a7b576000612a7e565b60025b6001600160a01b038716731bbe271d15bb64df0bc6cd28df9ff322f2ebd84714612aa9576000612aac565b60015b010160ff16905081600f0b60001480612ac8575080600f0b6000145b15612ad4575050611294565b612b026001600160a01b038716739726e9314ef1b96e45f40056bed61a088897313e8663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151739726e9314ef1b96e45f40056bed61a088897313e92633df02124926084808201939182900301818387803b15801561127957600080fd5b612ba66001600160a01b0385167303ef3f37856bd08eb47e2de7abc4ddd2c19b60f28463ffffffff6134ba16565b60408051630df791e560e41b81526001600160a01b038681166004830152851660248201526044810184905290517303ef3f37856bd08eb47e2de7abc4ddd2c19b60f29163df791e5091606480830192600092919082900301818387803b158015612c1057600080fd5b505af1158015610e31573d6000803e3d6000fd5b612c526001600160a01b03851673a8253a440be331dc4a7395b73948cca6f19dc97d8463ffffffff6134ba16565b604080516303ff4c0160e31b81526001600160a01b0386811660048301528516602482015260448101849052600060648201819052603242016084830152915173a8253a440be331dc4a7395b73948cca6f19dc97d92631ffa60089260a480820193602093909283900390910190829087803b158015612cd157600080fd5b505af1158015612ce5573d6000803e3d6000fd5b505050506040513d6020811015610a9f57600080fd5b612d296001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a58463ffffffff6134ba16565b60408051631ba0488760e21b81526001600160a01b0386811660048301528516602482015260448101849052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b158015612cd157600080fd5b60006001600160a01b03851673fe18be6b3bd88a2d2a7f928d00292e7a9963cfc614612dc7576000612dca565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612df5576000612df8565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612e23576000612e26565b60015b010160ff169050600073fe18be6b3bd88a2d2a7f928d00292e7a9963cfc66001600160a01b0316856001600160a01b031614612e63576000612e66565b60035b6001600160a01b038616732260fac5e5542a773aa44fbcfedf7c193bc2c59914612e91576000612e94565b60025b6001600160a01b03871673eb4c2781e4eba804ce9a9803c67d0893436bb27d14612ebf576000612ec2565b60015b010160ff16905081600f0b60001480612ede575080600f0b6000145b15612eea575050611294565b612f186001600160a01b038716737fc77b5c7614e1533320ea6ddc2eb61fa00a97148663ffffffff6134ba16565b60408051630f7c084960e21b8152600019808501600f90810b810b6004840152908401810b900b6024820152604481018690526000606482018190529151737fc77b5c7614e1533320ea6ddc2eb61fa00a971492633df02124926084808201939182900301818387803b15801561127957600080fd5b611294848484846000613a5e565b611294848484846001613a5e565b611294848484846002613a5e565b611294848484846001685a434ecd46efdcc7c760b11b0319613ecf565b61129484848484600161543360e81b0319613ecf565b6112948484848460016b2c2466af65a2f7eba2a7a463609a1b0319613ecf565b6112948484848461301c89896146ff565b613ecf565b61302e8460008484612347565b6112946000844784612347565b613055846000805160206150868339815191528484612347565b604080516370a0823160e01b815230600482015290516112949160008051602061508683398151915291869183916370a0823191602480820192602092909190829003018186803b1580156130a957600080fd5b505afa1580156130bd573d6000803e3d6000fd5b505050506040513d60208110156130d357600080fd5b505184612347565b6130f5846000805160206150f28339815191528484612347565b604080516370a0823160e01b81523060048201529051611294916000805160206150f283398151915291869183916370a0823191602480820192602092909190829003018186803b1580156130a957600080fd5b6000828201838110156131a3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60006001600160a01b03821615806131a657506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b806131ef57611294565b6131f8846131ac565b156132dc576001600160a01b038316331480156132155750803410155b6132505760405162461bcd60e51b815260040180806020018281038252602b8152602001806150a6602b913960400191505060405180910390fd5b6001600160a01b0382163014613298576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015613296573d6000803e3d6000fd5b505b80341115611eb357336108fc6132b4348463ffffffff61497a16565b6040518115909202916000818181858888f19350505050158015611c6d573d6000803e3d6000fd5b6112946001600160a01b03851684848463ffffffff6149bc16565b6000613302836131ac565b1561331857506001600160a01b038116316131a6565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561336e57600080fd5b505afa158015613382573d6000803e3d6000fd5b505050506040513d602081101561339857600080fd5b505190506131a6565b6000826133b0575060006131a6565b828202828482816133bd57fe5b04146131a35760405162461bcd60e51b81526004018080602001828103825260218152602001806150d16021913960400191505060405180910390fd5b60006131a383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614a16565b60008161344b575060016134b3565b613454846131ac565b15613495576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561348f573d6000803e3d6000fd5b506134b3565b6134af6001600160a01b038516848463ffffffff614ab816565b5060015b9392505050565b6134c3836131ac565b6135ae57806134ec576134e76001600160a01b03841683600063ffffffff614b0a16565b6135ae565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b15801561353d57600080fd5b505afa158015613551573d6000803e3d6000fd5b505050506040513d602081101561356757600080fd5b5051905081811015611294578015613594576135946001600160a01b03851684600063ffffffff614b0a16565b6112946001600160a01b038516848463ffffffff614b0a16565b505050565b60006135c7856001600160a01b03166131ac565b1561362f576000805160206150668339815191526001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561361557600080fd5b505af1158015613629573d6000803e3d6000fd5b50505050505b6000613643866001600160a01b03166131ac565b61364d578561365d565b6000805160206150668339815191525b90506000613673866001600160a01b03166131ac565b61367d578561368d565b6000805160206150668339815191525b6040805163e6a4390560e01b81526001600160a01b038581166004830152831660248201529051919250600091735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9163e6a43905916044808301926020929190829003018186803b1580156136f557600080fd5b505afa158015613709573d6000803e3d6000fd5b505050506040513d602081101561371f57600080fd5b505190506000806137416001600160a01b03841686868b63ffffffff614c1d16565b9197509250905081156137a657826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561378957600080fd5b505af115801561379d573d6000803e3d6000fd5b50505050613820565b8015613820576040805163bc25cf7760e01b81527368a17b587caf4f9329f0e372e3a78d23a46de6b5600482015290516001600160a01b0385169163bc25cf7791602480830192600092919082900301818387803b15801561380757600080fd5b505af115801561381b573d6000803e3d6000fd5b505050505b61383a6001600160a01b038616848a63ffffffff61343c16565b50836001600160a01b0316856001600160a01b031610156138d3576040805163022c0d9f60e01b815260006004820181905260248201899052306044830152608060648301526084820181905291516001600160a01b0386169263022c0d9f9260c4808201939182900301818387803b1580156138b657600080fd5b505af11580156138ca573d6000803e3d6000fd5b5050505061394d565b6040805163022c0d9f60e01b815260048101889052600060248201819052306044830152608060648301526084820181905291516001600160a01b0386169263022c0d9f9260c4808201939182900301818387803b15801561393457600080fd5b505af1158015613948573d6000803e3d6000fd5b505050505b61395f896001600160a01b03166131ac565b15613a3a57604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b1580156139b757600080fd5b505afa1580156139cb573d6000803e3d6000fd5b505050506040513d60208110156139e157600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015613a2157600080fd5b505af1158015613a35573d6000803e3d6000fd5b505050505b5050505050949350505050565b610a9f8484613a58888887876135b3565b846135b3565b60607365e67cbc342712df67494acefc06fe951ee9398263bfdbfc43613a8c6001600160a01b0389166131ac565b613a965787613aa6565b6000805160206150668339815191525b613ab8886001600160a01b03166131ac565b613ac25787613ad2565b6000805160206150668339815191525b856001016040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060006040518083038186803b158015613b3c57600080fd5b505afa158015613b50573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015613b7957600080fd5b8101908080516040519392919084600160201b821115613b9857600080fd5b908301906020820185811115613bad57600080fd5b82518660208202830111600160201b82111715613bc957600080fd5b82525081516020918201928201910280838360005b83811015613bf6578181015183820152602001613bde565b505050509050016040525050509050613c17866001600160a01b03166131ac565b15613c7f576000805160206150668339815191526001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c6557600080fd5b505af1158015613c79573d6000803e3d6000fd5b50505050505b613cd9818381518110613c8e57fe5b602002602001015185613ca9896001600160a01b03166131ac565b613cb35788613cc3565b6000805160206150668339815191525b6001600160a01b0316919063ffffffff6134ba16565b808281518110613ce557fe5b60200260200101516001600160a01b0316638201aa3f613d0d886001600160a01b03166131ac565b613d175787613d27565b6000805160206150668339815191525b86613d3a896001600160a01b03166131ac565b613d445788613d54565b6000805160206150668339815191525b60006000196040518663ffffffff1660e01b815260040180866001600160a01b03166001600160a01b03168152602001858152602001846001600160a01b03166001600160a01b03168152602001838152602001828152602001955050505050506040805180830381600087803b158015613dce57600080fd5b505af1158015613de2573d6000803e3d6000fd5b505050506040513d6040811015613df857600080fd5b50613e0d90506001600160a01b0386166131ac565b15610a9f57604080516370a0823160e01b8152306004820152905160008051602061506683398151915291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015613e6557600080fd5b505afa158015613e79573d6000803e3d6000fd5b505050506040513d6020811015613e8f57600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b15801561127957600080fd5b604080516001808252818301909252849160609190602080830190803883390190505090508281600081518110613f0257fe5b602002602001018181525050613f20876001600160a01b03166131ac565b61432157606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166361e597f9896001856000604051908082528060200260200182016040528015613f78578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b03168152602001846003811115613fb057fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b83811015613ff8578181015183820152602001613fe0565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561403757818101518382015260200161401f565b50505050905001965050505050505060006040518083038186803b15801561405e57600080fd5b505afa158015614072573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561409b57600080fd5b8101908080516040519392919084600160201b8211156140ba57600080fd5b9083019060208201858111156140cf57600080fd5b8251600160201b8111828201881017156140e857600080fd5b82525081516020918201929091019080838360005b838110156141155781810151838201526020016140fd565b50505050905090810190601f1680156141425780820380516001836020036101000a031916815260200191505b506040525091925061417b9150506001600160a01b038916739aab3f75489902f3a48495025729a0af77d4b11e8863ffffffff6134ba16565b739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d54898573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee3060001960007368a17b587caf4f9329f0e372e3a78d23a46de6b560ff8e901c600a028a6040518a63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561429d578181015183820152602001614285565b50505050905090810190601f1680156142ca5780820380516001836020036101000a031916815260200191505b509a5050505050505050505050602060405180830381600087803b1580156142f157600080fd5b505af1158015614305573d6000803e3d6000fd5b505050506040513d602081101561431b57600080fd5b50519250505b614333866001600160a01b03166131ac565b61255757606073a1c0fa73c39cfbcc11ec9eb1afc665aba9996e2c6001600160a01b03166381efcbdd88600185600060405190808252806020026020018201604052801561438b578160200160208202803883390190505b506040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b031681526020018460038111156143c357fe5b60ff1681526020018060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561440b5781810151838201526020016143f3565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561444a578181015183820152602001614432565b50505050905001965050505050505060006040518083038186803b15801561447157600080fd5b505afa158015614485573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156144ae57600080fd5b8101908080516040519392919084600160201b8211156144cd57600080fd5b9083019060208201858111156144e257600080fd5b8251600160201b8111828201881017156144fb57600080fd5b82525081516020918201929091019080838360005b83811015614528578181015183820152602001614510565b50505050905090810190601f1680156145555780820380516001836020036101000a031916815260200191505b506040525050509050739aab3f75489902f3a48495025729a0af77d4b11e6001600160a01b031663ae591d548473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868b3060001960007368a17b587caf4f9329f0e372e3a78d23a46de6b560ff8f901c600a028b6040518b63ffffffff1660e01b8152600401808a6001600160a01b03166001600160a01b03168152602001898152602001886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001868152602001858152602001846001600160a01b03166001600160a01b0316815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b83811015614681578181015183820152602001614669565b50505050905090810190601f1680156146ae5780820380516001836020036101000a031916815260200191505b509a50505050505050505050506020604051808303818588803b1580156146d457600080fd5b505af11580156146e8573d6000803e3d6000fd5b50505050506040513d602081101561128d57600080fd5b6000614713836001600160a01b03166131ac565b15801561472f575061472d826001600160a01b03166131ac565b155b1561473c575060006131a6565b606073c8fb12402cb16970f3c5f4b48ff68eb9d1289301633d3dc52c61476a6001600160a01b0387166131ac565b6147745785614776565b845b6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060006040518083038186803b1580156147bc57600080fd5b505afa1580156147d0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156147f957600080fd5b8101908080516040519392919084600160201b82111561481857600080fd5b90830190602082018581111561482d57600080fd5b82518660208202830111600160201b8211171561484957600080fd5b82525081516020918201928201910280838360005b8381101561487657818101518382015260200161485e565b50505050905001604052505050905060008090505b815181101561496f5760f88282815181106148a257fe5b602002602001015160001c901c60bb141580156148e557508181815181106148c657fe5b60200260200101516001685a434ecd46efdcc7c760b11b031960001b14155b801561491057508181815181106148f857fe5b6020026020010151600161543360e81b031960001b14155b8015614945575081818151811061492357fe5b602002602001015160016b2c2466af65a2f7eba2a7a463609a1b031960001b14155b156149675781818151811061495657fe5b6020026020010151925050506131a6565b60010161488b565b506000949350505050565b60006131a383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614dd6565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611294908590614e30565b60008183614aa25760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614a67578181015183820152602001614a4f565b50505050905090810190601f168015614a945780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581614aae57fe5b0495945050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526135ae908490614e30565b801580614b90575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015614b6257600080fd5b505afa158015614b76573d6000803e3d6000fd5b505050506040513d6020811015614b8c57600080fd5b5051155b614bcb5760405162461bcd60e51b81526004018080602001828103825260368152602001806151626036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526135ae908490614e30565b6000808080614c3b6001600160a01b0388168963ffffffff6132f716565b90506000614c586001600160a01b0388168a63ffffffff6132f716565b90506000808a6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015614c9657600080fd5b505afa158015614caa573d6000803e3d6000fd5b505050506040513d6060811015614cc057600080fd5b50805160209091015190925090506001600160a01b03808a16908b161115614ce457905b816001600160701b0316841080614d035750806001600160701b031683105b955085158015614d2d5750816001600160701b0316841180614d2d5750806001600160701b031683115b94506000614d43896103e563ffffffff6133a116565b90506000614d6a614d5d86856001600160701b0316614fe8565b839063ffffffff6133a116565b90506000614da383614d976103e8614d8b8b8a6001600160701b0316614fe8565b9063ffffffff6133a116565b9063ffffffff61314916565b90508015614dc057614dbb828263ffffffff6133fa16565b614dc3565b60005b9950505050505050509450945094915050565b60008184841115614e285760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315614a67578181015183820152602001614a4f565b505050900390565b614e42826001600160a01b0316614ffe565b614e93576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310614ed15780518252601f199092019160209182019101614eb2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614f33576040519150601f19603f3d011682016040523d82523d6000602084013e614f38565b606091505b509150915081614f8f576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561129457808060200190516020811015614fab57600080fd5b50516112945760405162461bcd60e51b815260040180806020018281038252602a815260200180615138602a913960400191505060405180910390fd5b6000818310614ff757816131a3565b5090919050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061503257508115155b949350505050565b6040518061044001604052806022905b61506381526020019060019003908161504a5790505090565bfefe000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d2829536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb484f6e6553706c69743a2052657475726e20616d6f756e7420776173206e6f7420656e6f7567685361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e63654f6e6553706c69743a20446973747269627574696f6e2061727261792073686f756c64206e6f74206578636565642072657365727665732061727261792073697a65a265627a7a72315820a7810b563a2b3b8d2c6de6f3026721a61f47df98505f5574f26361201e0559cf64736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001a3f7583c0af24ef78cdb1a1eb48d957df793824
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x1A3f7583C0Af24ef78CdB1a1eB48D957df793824
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001a3f7583c0af24ef78cdb1a1eb48d957df793824
Deployed Bytecode Sourcemap
129946:25649:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;130249:10;130263:9;130249:23;;130241:32;;;;;;129946:25649;130289:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;130289:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;130289: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;130289:515:0;;;;;;;;;;;;;;;;;;130812:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;130812:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;130812: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;130812:627:0;;;;;;;;;;;;;;;;;;;131447:3064;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;131447:3064:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;131447:3064:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;131447:3064: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;131447:3064:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;131447:3064:0;;-1:-1:-1;;131447:3064:0;;;-1:-1:-1;131447:3064:0;;-1:-1:-1;;131447:3064:0:i;:::-;;;;;;;;;;;;;;;;129998:33;;8:9:-1;5:2;;;30:1;27;20:12;5:2;129998:33:0;;;:::i;:::-;;;;-1:-1:-1;;;;;129998:33:0;;;;;;;;;;;;;;130289:515;130511:20;130546:29;130636:160;130675:9;130699;130723:6;130744:5;130764;130784:1;130636:24;:160::i;:::-;130603:193;;;;-1:-1:-1;130289:515:0;;-1:-1:-1;;;;;;;130289:515:0:o;130812:627::-;131090:20;131229:12;;:202;;;-1:-1:-1;;;131229:202:0;;-1:-1:-1;;;;;131229:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;131090:20;;131165:29;;131229:12;;:37;;:202;;;;;131090:20;;131229:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;131229:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;131229:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;131229: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;131229: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;131229:202:0;;421:4:-1;412:14;;;;131229:202:0;;;;;412:14:-1;131229: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;131229:202:0;;;;;;;;;;;131222:209;;;;;;130812:627;;;;;;;;;;:::o;131447:3064::-;131697:20;131747:9;-1:-1:-1;;;;;131734:22:0;:9;-1:-1:-1;;;;;131734:22:0;;131730:68;;;-1:-1:-1;131780:6:0;131773:13;;131730:68;131810;;:::i;:::-;:1152;;;;;;;;131896:14;131810:1152;;;;131925:14;131810:1152;;;;131954:13;131810:1152;;;;131982:12;131810:1152;;;;132009:20;131810:1152;;;;132044:16;131810:1152;;;;132075:13;131810:1152;;;;132103:19;131810:1152;;;;132137:21;131810:1152;;;;132173:22;131810:1152;;;;132210:18;131810:1152;;;;132243:18;131810:1152;;;;132276:16;131810:1152;;;;132307:16;131810:1152;;;;132338:19;131810:1152;;;;132372:19;131810:1152;;;;132406:20;131810:1152;;;;132441:15;131810:1152;;;;132471:18;131810:1152;;;;132504:16;131810:1152;;;;132535:17;131810:1152;;;;132567:12;131810:1152;;;;132594:18;131810:1152;;;;132627:16;131810:1152;;;;132658:16;131810:1152;;;;132689:16;131810:1152;;;;132720:16;131810:1152;;;;132751:13;131810:1152;;;;132779:13;131810:1152;;;;132807:13;131810:1152;;;;132835:13;131810:1152;;;;132863:19;131810:1152;;;;132897:19;131810:1152;;;;132931:20;131810:1152;;;;;133006:15;132983:12;:19;:38;;132975:117;;;;-1:-1:-1;;;132975:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;133105:13;;;133172:206;133193:12;:19;133189:1;:23;133172:206;;;133256:1;133238:12;133251:1;133238:15;;;;;;;;;;;;;;:19;133234:133;;;133286:26;133296:12;133309:1;133296:15;;;;;;;;;;;;;;133286:5;:9;;:26;;;;:::i;:::-;133278:34;;133350:1;133331:20;;133234:133;133214:3;;133172:206;;;-1:-1:-1;133394:10:0;133390:193;;133425:17;:9;-1:-1:-1;;;;;133425:15:0;;:17::i;:::-;133421:123;;;133463:30;;:10;;133483:9;133463:30;;;;;;;;;133483:9;133463:10;:30;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;133463:30:0;133519:9;133512:16;;;;;;;133421:123;133565:6;133558:13;;;;;;;133390:193;133595:66;-1:-1:-1;;;;;133595:31:0;;133627:10;133647:4;133654:6;133595:66;:31;:66;:::i;:::-;133672:23;133698:43;-1:-1:-1;;;;;133698:28:0;;133735:4;133698:43;:28;:43;:::i;:::-;133672:69;-1:-1:-1;133759:6:0;133754:433;133775:12;:19;133771:1;:23;133754:433;;;133820:12;133833:1;133820:15;;;;;;;;;;;;;;133839:1;133820:20;133816:69;;;133861:8;;133816:69;133901:18;133922:38;133954:5;133922:27;133933:12;133946:1;133933:15;;;;;;;;;;;;;;133922:6;:10;;:27;;;;:::i;:::-;:31;:38;:31;:38;:::i;:::-;133901:59;;133984:16;133979:1;:21;133975:90;;;-1:-1:-1;134034:15:0;133975:90;134098:10;134079:29;;;;134123:52;134135:9;134146;134157:10;134169:5;134123:8;134132:1;134123:11;;;;;;;;;;;:52;;:::i;:::-;133754:433;;133796:3;;133754:433;;;-1:-1:-1;134214:43:0;-1:-1:-1;;;;;134214:28:0;;134251:4;134214:43;:28;:43;:::i;:::-;134199:58;;134292:9;134276:12;:25;;134268:76;;;;-1:-1:-1;;;134268:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;134355:53;-1:-1:-1;;;;;134355:27:0;;134383:10;134395:12;134355:53;:27;:53;:::i;:::-;-1:-1:-1;134419:84:0;134447:10;134459:43;-1:-1:-1;;;;;134459:28:0;;134496:4;134459:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;134419:27:0;;;:84;;:27;:84;:::i;:::-;;131447:3064;;;;;;;;;;;;;:::o;129998:33::-;;;-1:-1:-1;;;;;129998:33:0;;:::o;141398:859::-;141579:6;141603:17;-1:-1:-1;;;;;141603:15:0;;;:17::i;:::-;141598:361;;141669:37;;;-1:-1:-1;;;141669:37:0;;-1:-1:-1;;;;;141669:37:0;;;;;;;;141637:29;;73482:42;;141669:26;;:37;;;;;;;;;;;;;;;73482:42;141669:37;;;5:2:-1;;;;30:1;27;20:12;5:2;141669:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;141669:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;141669:37:0;;-1:-1:-1;;;;;;141725:35:0;;;141721:227;;141781:63;-1:-1:-1;;;;;141781:26:0;;141816:12;141831;141781:63;:26;:63;:::i;:::-;141878:54;;;-1:-1:-1;;;141878:54:0;;;;;;;;141925:1;141878:54;;;;141928:3;141878:54;;;;;;-1:-1:-1;;;;;141878:32:0;;;;;:54;;;;;;;;;;;;;;-1:-1:-1;141878:32:0;:54;;;5:2:-1;;;;30:1;27;20:12;5:2;141878:54:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;141878:54:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;141878:54:0;;-1:-1:-1;141721:227:0;141598:361;;141976:17;:9;-1:-1:-1;;;;;141976:15:0;;:17::i;:::-;141971:279;;142040:37;;;-1:-1:-1;;;142040:37:0;;-1:-1:-1;;;;;142040:37:0;;;;;;;;142010:27;;73482:42;;142040:26;;:37;;;;;;;;;;;;;;;73482:42;142040:37;;;5:2:-1;;;;30:1;27;20:12;5:2;142040:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142040:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142040:37:0;;-1:-1:-1;;;;;;142096:33:0;;;142092:147;;142165:10;-1:-1:-1;;;;;142165:30:0;;142202:12;142216:1;142219:3;142165:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;142165:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142165:58:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142165:58:0;;-1:-1:-1;142092:147:0;141971:279;;141398:859;;;;;:::o;146279:214::-;146449:36;;;-1:-1:-1;;;146449:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;149673:625;149830:28;73623:42;-1:-1:-1;;;;;149876:32:0;;:49;;;;;;;;;;;;;-1:-1:-1;;;149876:49:0;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149876:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149876:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;149876:49:0;;-1:-1:-1;149937:21:0;73767:42;149961:36;150012:17;-1:-1:-1;;;;;150012:15:0;;;:17::i;:::-;:48;;150051:9;150012:48;;;71761:42;150012:48;150075:17;:9;-1:-1:-1;;;;;150075:15:0;;:17::i;:::-;:48;;150114:9;150075:48;;;71761:42;150075:48;149961:173;;;;;;;;;;;;;-1:-1:-1;;;;;149961:173:0;-1:-1:-1;;;;;149961:173:0;;;;;;-1:-1:-1;;;;;149961:173:0;-1:-1:-1;;;;;149961:173:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149961:173:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149961:173:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;149961: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;149961: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;149961:173:0;;421:4:-1;412:14;;;;149961:173:0;;;;;412:14:-1;149961: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;149961:173:0;;;;;;;;;;;149937:197;;150145:58;150180:13;150196:6;150145:9;-1:-1:-1;;;;;150145:26:0;;;:58;;;;;:::i;:::-;150214:13;-1:-1:-1;;;;;150214:21:0;;150242:17;:9;-1:-1:-1;;;;;150242:15:0;;:17::i;:::-;:30;;150271:1;150242:30;;;150262:6;150242:30;150274:4;150280:6;150288:1;150214: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;150214:76:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;150214:76:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150214:76:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;;149673:625:0:o;150306:678::-;150466:17;:9;-1:-1:-1;;;;;150466:15:0;;:17::i;:::-;150462:78;;;-1:-1:-1;;;;;;;;;;;;;;;;150500:12:0;;150519:6;150500:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;150500:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150500:28:0;;;;;150462:78;150552:19;150574:17;:9;-1:-1:-1;;;;;150574:15:0;;:17::i;:::-;:36;;150601:9;150574:36;;;-1:-1:-1;;;;;;;;;;;150574:36:0;150552:58;-1:-1:-1;150621:61:0;-1:-1:-1;;;;;150621:29:0;;74138:42;150675:6;150621:61;:29;:61;:::i;:::-;74138:42;150693:27;150735:17;-1:-1:-1;;;;;150735:15:0;;;:17::i;:::-;:36;;150762:9;150735:36;;;-1:-1:-1;;;;;;;;;;;150735:36:0;150786:6;150807:17;:9;-1:-1:-1;;;;;150807:15:0;;:17::i;:::-;:36;;150834:9;150807:36;;;-1:-1:-1;;;;;;;;;;;150807:36:0;150693:177;;;-1:-1:-1;;;;;;150693:177:0;;;;;;;-1:-1:-1;;;;;150693:177:0;;;;;;;;;;;;;;;;;;;;150858:1;150693:177;;;;;;;;;;;;;;;;;;;;-1:-1:-1;150693:177:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;150693:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150693:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;150887:17:0;;-1:-1:-1;;;;;;150887:15:0;;;:17::i;:::-;150883:94;;;150935:29;;;-1:-1:-1;;;150935:29:0;;150958:4;150935:29;;;;;;-1:-1:-1;;;;;;;;;;;71848:42:0;150921:13;;71848:42;;150935:14;;:29;;;;;;;;;;;;;;71848:42;150935:29;;;5:2:-1;;;;30:1;27;20:12;5:2;150935:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150935:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;150935:29:0;150921:44;;;-1:-1:-1;;;;;;150921:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;150921:44:0;;;;;;;-1:-1:-1;150921:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;150921:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;150921:44:0;;;;150306:678;;;;;:::o;134542:522::-;134706:8;-1:-1:-1;;;;;134747:17:0;;-1:-1:-1;;;;;;;;;;;134747:17:0;:25;;134771:1;134747:25;;;134767:1;134747:25;-1:-1:-1;;;;;134718:16:0;;-1:-1:-1;;;;;;;;;;;134718:16:0;:24;;134741:1;134718:24;;;134737:1;134718:24;134717:56;134706:67;;;-1:-1:-1;134784:8:0;-1:-1:-1;;;;;;;;;;;;;;;;134825:17:0;;;:25;;134849:1;134825:25;;;134845:1;134825:25;-1:-1:-1;;;;;134796:16:0;;-1:-1:-1;;;;;;;;;;;134796:16:0;:24;;134819:1;134796:24;;;134815:1;134796:24;134795:56;134784:67;;;;134866:1;:6;;134871:1;134866:6;:16;;;;134876:1;:6;;134881:1;134876:6;134866:16;134862:55;;;134899:7;;;;134862:55;134929:58;-1:-1:-1;;;;;134929:26:0;;74236:42;134980:6;134929:58;:26;:58;:::i;:::-;134998;;;-1:-1:-1;;;134998:58:0;;-1:-1:-1;;135032:5:0;;;134998:58;;;;;;;;;;135039:5;;;134998:58;;;;;;;;;;;;;;135054:1;134998:58;;;;;;;;74236:42;;134998:33;;:58;;;;;;;;;;;135054:1;74236:42;134998:58;;;5:2:-1;;;;30:1;27;20:12;5:2;134998:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;134998:58:0;;;;134542:522;;;;;;;:::o;135072:622::-;135232:8;-1:-1:-1;;;;;135329:17:0;;72201:42;135329:17;:25;;135353:1;135329:25;;;135349:1;135329:25;-1:-1:-1;;;;;135286:17:0;;-1:-1:-1;;;;;;;;;;;135286:17:0;:25;;135310:1;135286:25;;;135306:1;135286:25;-1:-1:-1;;;;;135244:16:0;;-1:-1:-1;;;;;;;;;;;135244:16:0;:24;;135267:1;135244:24;;;135263:1;135244:24;135243:69;:112;135232:123;;;;135366:8;72201:42;-1:-1:-1;;;;;135463:17:0;:9;-1:-1:-1;;;;;135463:17:0;;:25;;135487:1;135463:25;;;135483:1;135463:25;-1:-1:-1;;;;;135420:17:0;;-1:-1:-1;;;;;;;;;;;135420:17:0;:25;;135444:1;135420:25;;;135440:1;135420:25;-1:-1:-1;;;;;135378:16:0;;-1:-1:-1;;;;;;;;;;;135378:16:0;:24;;135401:1;135378:24;;;135397:1;135378:24;135377:69;:112;135366:123;;;;135504:1;:6;;135509:1;135504:6;:16;;;;135514:1;:6;;135519:1;135514:6;135504:16;135500:55;;;135537:7;;;;135500:55;135567:54;-1:-1:-1;;;;;135567:26:0;;74330:42;135614:6;135567:54;:26;:54;:::i;:::-;135632;;;-1:-1:-1;;;135632:54:0;;-1:-1:-1;;135662:5:0;;;135632:54;;;;;;;;;;135669:5;;;135632:54;;;;;;;;;;;;;;135684:1;135632:54;;;;;;;;74330:42;;135632:29;;:54;;;;;;;;;;;135684:1;74330:42;135632:54;;;5:2:-1;;;;30:1;27;20:12;135702:699:0;135859:8;-1:-1:-1;;;;;135999:17:0;;72290:42;135999:17;:25;;136023:1;135999:25;;;136019:1;135999:25;-1:-1:-1;;;;;135956:17:0;;72201:42;135956:17;:25;;135980:1;135956:25;;;135976:1;135956:25;-1:-1:-1;;;;;135913:17:0;;-1:-1:-1;;;;;;;;;;;135913:17:0;:25;;135937:1;135913:25;;;135933:1;135913:25;-1:-1:-1;;;;;135871:16:0;;-1:-1:-1;;;;;;;;;;;135871:16:0;:24;;135894:1;135871:24;;;135890:1;135871:24;135870:69;:112;:155;135859:166;;;;136036:8;72290:42;-1:-1:-1;;;;;136176:17:0;:9;-1:-1:-1;;;;;136176:17:0;;:25;;136200:1;136176:25;;;136196:1;136176:25;-1:-1:-1;;;;;136133:17:0;;72201:42;136133:17;:25;;136157:1;136133:25;;;136153:1;136133:25;-1:-1:-1;;;;;136090:17:0;;-1:-1:-1;;;;;;;;;;;136090:17:0;:25;;136114:1;136090:25;;;136110:1;136090:25;-1:-1:-1;;;;;136048:16:0;;-1:-1:-1;;;;;;;;;;;136048:16:0;:24;;136071:1;136048:24;;;136067:1;136048:24;136047:69;:112;:155;136036:166;;;;136217:1;:6;;136222:1;136217:6;:16;;;;136227:1;:6;;136232:1;136227:6;136217:16;136213:55;;;136250:7;;;;136213:55;136280:51;-1:-1:-1;;;;;136280:26:0;;74421:42;136324:6;136280:51;:26;:51;:::i;:::-;136342;;;-1:-1:-1;;;136342:51:0;;-1:-1:-1;;136369:5:0;;;136342:51;;;;;;;;;;136376:5;;;136342:51;;;;;;;;;;;;;;136391:1;136342:51;;;;;;;;74421:42;;136342:26;;:51;;;;;;;;;;;136391:1;74421:42;136342:51;;;5:2:-1;;;;30:1;27;20:12;136409:717:0;136572:8;-1:-1:-1;;;;;136712:17:0;;72379:42;136712:17;:25;;136736:1;136712:25;;;136732:1;136712:25;-1:-1:-1;;;;;136669:17:0;;72201:42;136669:17;:25;;136693:1;136669:25;;;136689:1;136669:25;-1:-1:-1;;;;;136626:17:0;;-1:-1:-1;;;;;;;;;;;136626:17:0;:25;;136650:1;136626:25;;;136646:1;136626:25;-1:-1:-1;;;;;136584:16:0;;-1:-1:-1;;;;;;;;;;;136584:16:0;:24;;136607:1;136584:24;;;136603:1;136584:24;136583:69;:112;:155;136572:166;;;;136749:8;72379:42;-1:-1:-1;;;;;136889:17:0;:9;-1:-1:-1;;;;;136889:17:0;;:25;;136913:1;136889:25;;;136909:1;136889:25;-1:-1:-1;;;;;136846:17:0;;72201:42;136846:17;:25;;136870:1;136846:25;;;136866:1;136846:25;-1:-1:-1;;;;;136803:17:0;;-1:-1:-1;;;;;;;;;;;136803:17:0;:25;;136827:1;136803:25;;;136823:1;136803:25;-1:-1:-1;;;;;136761:16:0;;-1:-1:-1;;;;;;;;;;;136761:16:0;:24;;136784:1;136761:24;;;136780:1;136761:24;136760:69;:112;:155;136749:166;;;;136930:1;:6;;136935:1;136930:6;:16;;;;136940:1;:6;;136945:1;136940:6;136930:16;136926:55;;;136963:7;;;;136926:55;136993:57;-1:-1:-1;;;;;136993:26:0;;74518:42;137043:6;136993:57;:26;:57;:::i;:::-;137061;;;-1:-1:-1;;;137061:57:0;;-1:-1:-1;;137094:5:0;;;137061:57;;;;;;;;;;137101:5;;;137061:57;;;;;;;;;;;;;;137116:1;137061:57;;;;;;;;74518:42;;137061:32;;:57;;;;;;;;;;;137116:1;74518:42;137061:57;;;5:2:-1;;;;30:1;27;20:12;137134:723:0;137299:8;-1:-1:-1;;;;;137439:17:0;;72468:42;137439:17;:25;;137463:1;137439:25;;;137459:1;137439:25;-1:-1:-1;;;;;137396:17:0;;72201:42;137396:17;:25;;137420:1;137396:25;;;137416:1;137396:25;-1:-1:-1;;;;;137353:17:0;;-1:-1:-1;;;;;;;;;;;137353:17:0;:25;;137377:1;137353:25;;;137373:1;137353:25;-1:-1:-1;;;;;137311:16:0;;-1:-1:-1;;;;;;;;;;;137311:16:0;:24;;137334:1;137311:24;;;137330:1;137311:24;137310:69;:112;:155;137299:166;;;;137476:8;72468:42;-1:-1:-1;;;;;137616:17:0;:9;-1:-1:-1;;;;;137616:17:0;;:25;;137640:1;137616:25;;;137636:1;137616:25;-1:-1:-1;;;;;137573:17:0;;72201:42;137573:17;:25;;137597:1;137573:25;;;137593:1;137573:25;-1:-1:-1;;;;;137530:17:0;;-1:-1:-1;;;;;;;;;;;137530:17:0;:25;;137554:1;137530:25;;;137550:1;137530:25;-1:-1:-1;;;;;137488:16:0;;-1:-1:-1;;;;;;;;;;;137488:16:0;:24;;137511:1;137488:24;;;137507:1;137488:24;137487:69;:112;:155;137476:166;;;;137657:1;:6;;137662:1;137657:6;:16;;;;137667:1;:6;;137672:1;137667:6;137657:16;137653:55;;;137690:7;;;;137653:55;137720:59;-1:-1:-1;;;;;137720:26:0;;74617:42;137772:6;137720:59;:26;:59;:::i;:::-;137790;;;-1:-1:-1;;;137790:59:0;;-1:-1:-1;;137825:5:0;;;137790:59;;;;;;;;;;137832:5;;;137790:59;;;;;;;;;;;;;;137847:1;137790:59;;;;;;;;74617:42;;137790:34;;:59;;;;;;;;;;;137847:1;74617:42;137790:59;;;5:2:-1;;;;30:1;27;20:12;142265:921:0;142432:17;:9;-1:-1:-1;;;;;142432:15:0;;:17::i;:::-;142427:380;;142496:41;;;-1:-1:-1;;;142496:41:0;;-1:-1:-1;;;;;142496:41:0;;;;;;;;142466:27;;76447:42;;142496:30;;:41;;;;;;;;;;;;;;;76447:42;142496:41;;;5:2:-1;;;;30:1;27;20:12;5:2;142496:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142496:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142496:41:0;;-1:-1:-1;142552:57:0;-1:-1:-1;;;;;142552:26:0;;142496:41;142602:6;142552:57;:26;:57;:::i;:::-;142624:12;-1:-1:-1;;;;;142624:17:0;;142642:6;142624:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;142624:25:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142624:25:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142664:110:0;;-1:-1:-1;142686:12:0;142701:9;142712:54;-1:-1:-1;;;;;142712:39:0;;142760:4;142712:54;:39;:54;:::i;:::-;142768:5;142664:14;:110::i;:::-;142789:7;;;142427:380;142824:17;:9;-1:-1:-1;;;;;142824:15:0;;:17::i;:::-;142819:360;;142886:41;;;-1:-1:-1;;;142886:41:0;;-1:-1:-1;;;;;142886:41:0;;;;;;;;142858:25;;76447:42;;142886:30;;:41;;;;;;;;;;;;;;;76447:42;142886:41;;;5:2:-1;;;;30:1;27;20:12;5:2;142886:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142886:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142886:41:0;;-1:-1:-1;142942:60:0;142957:9;142886:41;142988:6;142996:5;142942:14;:60::i;:::-;-1:-1:-1;;;;;143017:17:0;;;143035:52;143017:17;143081:4;143035:52;:37;:52;:::i;:::-;143017:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;143017:71:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;143017:71:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;143103:43:0;;-1:-1:-1;;;;;;143103:28:0;;143140:4;143103:43;:28;:43;:::i;:::-;;143161:7;;;143194:646;-1:-1:-1;;;;;143356:16:0;;-1:-1:-1;;;;;;;;;;;143356:16:0;143352:275;;;143389:49;-1:-1:-1;;;;;143389:26:0;;71935:42;143431:6;143389:49;:26;:49;:::i;:::-;143453:32;;;-1:-1:-1;;;143453:32:0;;143471:4;143453:32;;;;;;;;;;;;71935:42;;143453:9;;:32;;;;;-1:-1:-1;;143453:32:0;;;;;;;-1:-1:-1;71935:42:0;143453:32;;;5:2:-1;;;;30:1;27;20:12;5:2;143453:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;143500:94:0;;-1:-1:-1;71935:42:0;;-1:-1:-1;143529:9:0;;-1:-1:-1;143540:46:0;71935:42;143580:4;143540:46;:31;:46;:::i;:::-;143588:5;143500:14;:94::i;:::-;143609:7;;143352:275;-1:-1:-1;;;;;143643:16:0;;-1:-1:-1;;;;;;;;;;;143643:16:0;143639:194;;;143676:54;143691:9;71935:42;143716:6;143724:5;143676:14;:54::i;:::-;143770:29;;;-1:-1:-1;;;143770:29:0;;143763:4;143770:29;;;;;;;;71935:42;;143745:9;;143763:4;;71935:42;;143770:14;;:29;;;;;;;;;;;;;;71935:42;143770:29;;;5:2:-1;;;;30:1;27;20:12;5:2;143770:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;143770:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;143770:29:0;143745:55;;;-1:-1:-1;;;;;;143745:55:0;;;;;;;-1:-1:-1;;;;;143745:55:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;143745:55:0;;;;;;;-1:-1:-1;143745:55:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;143745:55:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;143745:55:0;;;;143815:7;;143848:800;144011:17;:9;-1:-1:-1;;;;;144011:15:0;;:17::i;:::-;144006:362;;144067:37;;;-1:-1:-1;;;144067:37:0;;-1:-1:-1;;;;;144067:37:0;;;;;;;;144045:19;;76558:42;;144067:26;;:37;;;;;;;;;;;;;;;76558:42;144067:37;;;5:2:-1;;;;30:1;27;20:12;5:2;144067:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144067:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144067:37:0;144146:11;;;-1:-1:-1;;;144146:11:0;;;;144067:37;;-1:-1:-1;144119:47:0;;75193:42;;144146:9;;:11;;;;;144067:37;;144146:11;;;;;;;75193:42;144146:11;;;5:2:-1;;;;30:1;27;20:12;5:2;144146:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144146:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144146:11:0;-1:-1:-1;;;;;144119:26:0;;;144159:6;144119:47;:26;:47;:::i;:::-;144181:37;;;-1:-1:-1;;;144181:37:0;;-1:-1:-1;;;;;144181:37:0;;;;;;;;;;;;144213:4;144181:37;;;;;;75193:42;;144181:12;;:37;;;;;-1:-1:-1;;144181:37:0;;;;;;;-1:-1:-1;75193:42:0;144181:37;;;5:2:-1;;;;30:1;27;20:12;5:2;144181:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144181:37:0;;;;144233:102;144255:8;144266:9;144277:50;144321:4;144284:8;-1:-1:-1;;;;;144277:35:0;;;:50;;;;:::i;144006:362::-;144385:17;:9;-1:-1:-1;;;;;144385:15:0;;:17::i;:::-;144380:261;;144439:37;;;-1:-1:-1;;;144439:37:0;;-1:-1:-1;;;;;144439:37:0;;;;;;;;144419:17;;76558:42;;144439:26;;:37;;;;;;;;;;;;;;;76558:42;144439:37;;;5:2:-1;;;;30:1;27;20:12;5:2;144439:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144439:37:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144439:37:0;;-1:-1:-1;144491:56:0;144506:9;144439:37;144533:6;144541:5;144491:14;:56::i;:::-;144576:31;;;-1:-1:-1;;;144576:31:0;;144601:4;144576:31;;;;;;-1:-1:-1;;;;;144562:13:0;;;;;;;144576:16;;:31;;;;;;;;;;;;;;144562:13;144576:31;;;5:2:-1;;;;30:1;27;20:12;5:2;144576:31:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144576:31:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144576:31:0;144562:46;;;-1:-1:-1;;;;;;144562:46:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;144562:46:0;;;;;;;-1:-1:-1;144562:46:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;144562:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144562:46:0;;;;144623:7;;;144656:694;144816:20;75523:42;144839:23;144877:17;-1:-1:-1;;;;;144877:15:0;;;:17::i;:::-;:44;;144912:9;144877:44;;;71677:1;144877:44;144936:17;:9;-1:-1:-1;;;;;144936:15:0;;:17::i;:::-;:44;;144971:9;144936:44;;;71677:1;144936:44;144839:152;;;;;;;;;;;;;-1:-1:-1;;;;;144839:152:0;-1:-1:-1;;;;;144839:152:0;;;;;;-1:-1:-1;;;;;144839:152:0;-1:-1:-1;;;;;144839:152:0;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;144839:152:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;144839:152:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;144839:152:0;;-1:-1:-1;145002:54:0;-1:-1:-1;;;;;145002:26:0;;144839:152;145049:6;145002:54;:26;:54;:::i;:::-;145067:9;-1:-1:-1;;;;;145067:14:0;;145088:17;:9;-1:-1:-1;;;;;145088:15:0;;:17::i;:::-;:30;;145117:1;145088:30;;;145108:6;145088:30;145134:17;:9;-1:-1:-1;;;;;145134:15:0;;:17::i;:::-;:44;;145169:9;145134:44;;;71677:1;145134:44;145193:17;:9;-1:-1:-1;;;;;145193:15:0;;:17::i;:::-;:44;;145228:9;145193:44;;;71677:1;145193:44;145067:275;;;-1:-1:-1;;;;;;145067:275:0;;;;;;;-1:-1:-1;;;;;145067:275:0;;;;;;;;;;;;;;;;;;;;;145273:1;145067:275;;;;145289:42;145067:275;;;;;;;;;;;;;;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;145067:275:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;145067:275:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;144656:694:0:o;152717:288::-;152873:124;152912:9;152936;152960:6;152981:5;152873:24;:124::i;153013:309::-;153172:142;153210:9;-1:-1:-1;;;;;;;;;;;153253:9:0;153277:6;153298:5;153172:23;:142::i;153330:308::-;153489:141;153527:9;-1:-1:-1;;;;;;;;;;;153569:9:0;153593:6;153614:5;153489:23;:141::i;153646:310::-;153806:142;153844:9;-1:-1:-1;;;;;;;;;;;153887:9:0;153911:6;153932:5;153806:23;:142::i;137865:703::-;138024:8;-1:-1:-1;;;;;138164:16:0;;72556:42;138164:16;:24;;138187:1;138164:24;;;138183:1;138164:24;-1:-1:-1;;;;;138121:17:0;;72201:42;138121:17;:25;;138145:1;138121:25;;;138141:1;138121:25;-1:-1:-1;;;;;138078:17:0;;-1:-1:-1;;;;;;;;;;;138078:17:0;:25;;138102:1;138078:25;;;138098:1;138078:25;-1:-1:-1;;;;;138036:16:0;;-1:-1:-1;;;;;;;;;;;138036:16:0;:24;;138059:1;138036:24;;;138055:1;138036:24;138035:69;:112;:154;138024:165;;;;138200:8;72556:42;-1:-1:-1;;;;;138340:16:0;:9;-1:-1:-1;;;;;138340:16:0;;:24;;138363:1;138340:24;;;138359:1;138340:24;-1:-1:-1;;;;;138297:17:0;;72201:42;138297:17;:25;;138321:1;138297:25;;;138317:1;138297:25;-1:-1:-1;;;;;138254:17:0;;-1:-1:-1;;;;;;;;;;;138254:17:0;:25;;138278:1;138254:25;;;138274:1;138254:25;-1:-1:-1;;;;;138212:16:0;;-1:-1:-1;;;;;;;;;;;138212:16:0;:24;;138235:1;138212:24;;;138231:1;138212:24;138211:69;:112;:154;138200:165;;;;138380:1;:6;;138385:1;138380:6;:16;;;;138390:1;:6;;138395:1;138390:6;138380:16;138376:55;;;138413:7;;;;138376:55;138443:53;-1:-1:-1;;;;;138443:26:0;;74710:42;138489:6;138443:53;:26;:53;:::i;:::-;138507;;;-1:-1:-1;;;138507:53:0;;-1:-1:-1;;138536:5:0;;;138507:53;;;;;;;;;;138543:5;;;138507:53;;;;;;;;;;;;;;138558:1;138507:53;;;;;;;;74710:42;;138507:28;;:53;;;;;;;;;;;138558:1;74710:42;138507:53;;;5:2:-1;;;;30:1;27;20:12;139319:537:0;139481:8;-1:-1:-1;;;;;139538:17:0;;72736:42;139538:17;:25;;139562:1;139538:25;;;139558:1;139538:25;-1:-1:-1;;;;;139493:19:0;;72647:42;139493:19;:27;;139519:1;139493:27;;;139515:1;139493:27;139492:72;139481:83;;;-1:-1:-1;139575:8:0;72736:42;-1:-1:-1;;;;;139632:17:0;;;:25;;139656:1;139632:25;;;139652:1;139632:25;-1:-1:-1;;;;;139587:19:0;;72647:42;139587:19;:27;;139613:1;139587:27;;;139609:1;139587:27;139586:72;139575:83;;;;139673:1;:6;;139678:1;139673:6;:16;;;;139683:1;:6;;139688:1;139683:6;139673:16;139669:55;;;139706:7;;;;139669:55;139736:56;-1:-1:-1;;;;;139736:26:0;;74806:42;139785:6;139736:56;:26;:56;:::i;:::-;139803:45;;;-1:-1:-1;;;139803:45:0;;-1:-1:-1;;139824:5:0;;;139803:45;;;;;;;;;;139831:5;;;139803:45;;;;;;;;;;;;;;139846:1;139803:45;;;;;;;;74806:42;;139803:20;;:45;;;;;;;;;;;139846:1;74806:42;139803:45;;;5:2:-1;;;;30:1;27;20:12;139864:613:0;140024:8;-1:-1:-1;;;;;140122:17:0;;72914:42;140122:17;:25;;140146:1;140122:25;;;140142:1;140122:25;-1:-1:-1;;;;;140079:17:0;;72736:42;140079:17;:25;;140103:1;140079:25;;;140099:1;140079:25;-1:-1:-1;;;;;140036:17:0;;72825:42;140036:17;:25;;140060:1;140036:25;;;140056:1;140036:25;140035:70;:113;140024:124;;;;140159:8;72914:42;-1:-1:-1;;;;;140257:17:0;:9;-1:-1:-1;;;;;140257:17:0;;:25;;140281:1;140257:25;;;140277:1;140257:25;-1:-1:-1;;;;;140214:17:0;;72736:42;140214:17;:25;;140238:1;140214:25;;;140234:1;140214:25;-1:-1:-1;;;;;140171:17:0;;72825:42;140171:17;:25;;140195:1;140171:25;;;140191:1;140171:25;140170:70;:113;140159:124;;;;140298:1;:6;;140303:1;140298:6;:16;;;;140308:1;:6;;140313:1;140308:6;140298:16;140294:55;;;140331:7;;;;140294:55;140361:54;-1:-1:-1;;;;;140361:26:0;;74900:42;140408:6;140361:54;:26;:54;:::i;:::-;140426:43;;;-1:-1:-1;;;140426:43:0;;-1:-1:-1;;140445:5:0;;;140426:43;;;;;;;;;;140452:5;;;140426:43;;;;;;;;;;;;;;140467:1;140426:43;;;;;;;;74900:42;;140426:18;;:43;;;;;;;;;;;140467:1;74900:42;140426:43;;;5:2:-1;;;;30:1;27;20:12;141110:280:0;141271:55;-1:-1:-1;;;;;141271:26:0;;75744:42;141319:6;141271:55;:26;:55;:::i;:::-;141337:45;;;-1:-1:-1;;;141337:45:0;;-1:-1:-1;;;;;141337:45:0;;;;;;;;;;;;;;;;;;;;;75744:42;;141337:15;;:45;;;;;-1:-1:-1;;141337:45:0;;;;;;;-1:-1:-1;75744:42:0;141337:45;;;5:2:-1;;;;30:1;27;20:12;5:2;141337:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;138576:380:0;138732:50;-1:-1:-1;;;;;138732:26:0;;75084:42;138775:6;138732:50;:26;:50;:::i;:::-;138793:155;;;-1:-1:-1;;;138793:155:0;;-1:-1:-1;;;;;138793:155:0;;;;;;;;;;;;;;;;;;;138913:1;138793:155;;;;;;138935:2;138929:3;:8;138793:155;;;;;;75084:42;;138793:18;;:155;;;;;;;;;;;;;;;;;;75084:42;138793:155;;;5:2:-1;;;;30:1;27;20:12;5:2;138793:155:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;138793:155:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;138964:347:0;139126:49;-1:-1:-1;;;;;139126:26:0;;75837:42;139168:6;139126:49;:26;:49;:::i;:::-;139186:117;;;-1:-1:-1;;;139186:117:0;;-1:-1:-1;;;;;139186:117:0;;;;;;;;;;;;;;;;;;;139287:4;139186:117;;;;;;75837:42;;139186:9;;:117;;;;;;;;;;;;;;-1:-1:-1;75837:42:0;139186:117;;;5:2:-1;;;;30:1;27;20:12;140485:617:0;140645:8;-1:-1:-1;;;;;140745:17:0;;73003:42;140745:17;:25;;140769:1;140745:25;;;140765:1;140745:25;-1:-1:-1;;;;;140702:17:0;;72736:42;140702:17;:25;;140726:1;140702:25;;;140722:1;140702:25;-1:-1:-1;;;;;140657:19:0;;72647:42;140657:19;:27;;140683:1;140657:27;;;140679:1;140657:27;140656:72;:115;140645:126;;;;140782:8;73003:42;-1:-1:-1;;;;;140882:17:0;:9;-1:-1:-1;;;;;140882:17:0;;:25;;140906:1;140882:25;;;140902:1;140882:25;-1:-1:-1;;;;;140839:17:0;;72736:42;140839:17;:25;;140863:1;140839:25;;;140859:1;140839:25;-1:-1:-1;;;;;140794:19:0;;72647:42;140794:19;:27;;140820:1;140794:27;;;140816:1;140794:27;140793:72;:115;140782:126;;;;140923:1;:6;;140928:1;140923:6;:16;;;;140933:1;:6;;140938:1;140933:6;140923:16;140919:55;;;140956:7;;;;140919:55;140986:54;-1:-1:-1;;;;;140986:26:0;;74994:42;141033:6;140986:54;:26;:54;:::i;:::-;141051:43;;;-1:-1:-1;;;141051:43:0;;-1:-1:-1;;141070:5:0;;;141051:43;;;;;;;;;;141077:5;;;141051:43;;;;;;;;;;;;;;141092:1;141051:43;;;;;;;;74994:42;;141051:18;;:43;;;;;;;;;;;141092:1;74994:42;141051:43;;;5:2:-1;;;;30:1;27;20:12;154916:220:0;155072:56;155089:9;155100;155111:6;155119:5;155126:1;155072:16;:56::i;155144:220::-;155300:56;155317:9;155328;155339:6;155347:5;155354:1;155300:16;:56::i;155372:220::-;155528:56;155545:9;155556;155567:6;155575:5;155582:1;155528:16;:56::i;146501:354::-;146654:193;146681:9;146705;146729:6;146750:5;-1:-1:-1;;;;;;146654:12:0;:193::i;146863:354::-;147016:193;147043:9;147067;147091:6;147112:5;-1:-1:-1;;;;;;147016:12:0;:193::i;147225:354::-;147378:193;147405:9;147429;147453:6;147474:5;-1:-1:-1;;;;;;147378:12:0;:193::i;147587:333::-;147740:172;147767:9;147791;147815:6;147836:5;147856:45;147880:9;147891;147856:23;:45::i;:::-;147740:12;:172::i;145358:305::-;145517:56;145534:9;71677:1;145559:6;145567:5;145517:16;:56::i;:::-;145584:71;71677:1;145615:9;145626:21;145649:5;145584:16;:71::i;145671:294::-;145830:47;145847:9;-1:-1:-1;;;;;;;;;;;145863:6:0;145871:5;145830:16;:47::i;:::-;145921:28;;;-1:-1:-1;;;145921:28:0;;145943:4;145921:28;;;;;;145888:69;;-1:-1:-1;;;;;;;;;;;72023:42:0;145910:9;;72023:42;;145921:13;;:28;;;;;;;;;;;;;;;72023:42;145921:28;;;5:2:-1;;;;30:1;27;20:12;5:2;145921:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;145921:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;145921:28:0;145951:5;145888:16;:69::i;145973:298::-;146133:48;146150:9;-1:-1:-1;;;;;;;;;;;146167:6:0;146175:5;146133:16;:48::i;:::-;146226:29;;;-1:-1:-1;;;146226:29:0;;146249:4;146226:29;;;;;;146192:71;;-1:-1:-1;;;;;;;;;;;72112:42:0;146215:9;;72112:42;;146226:14;;:29;;;;;;;;;;;;;;;72112:42;146226:29;;;5:2:-1;;;;30:1;27;20:12;12663:181:0;12721:7;12753:5;;;12777:6;;;;12769:46;;;;;-1:-1:-1;;;12769:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;12835:1;-1:-1:-1;12663:181:0;;;;;:::o;42482:166::-;42533:4;-1:-1:-1;;;;;42558:39:0;;;;:81;;-1:-1:-1;;;;;;42601:38:0;;39654:42;42601:38;42550:90;42482:166;-1:-1:-1;;42482:166:0:o;40062:617::-;40173:11;40169:50;;40201:7;;40169:50;40235:12;40241:5;40235;:12::i;:::-;40231:441;;;-1:-1:-1;;;;;40272:18:0;;40280:10;40272:18;:41;;;;;40307:6;40294:9;:19;;40272:41;40264:97;;;;-1:-1:-1;;;40264:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;40380:19:0;;40394:4;40380:19;40376:97;;40420:37;;-1:-1:-1;;;;;40420:29:0;;;:37;;;;;40450:6;;40420:37;;;;40450:6;40420:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;40420:37:0;40376:97;40503:6;40491:9;:18;40487:101;;;40530:10;:42;40550:21;:9;40564:6;40550:21;:13;:21;:::i;:::-;40530:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;40231:441:0;40620:40;-1:-1:-1;;;;;40620:22:0;;40643:4;40649:2;40653:6;40620:40;:22;:40;:::i;41664:228::-;41742:7;41766:12;41772:5;41766;:12::i;:::-;41762:123;;;-1:-1:-1;;;;;;41802:11:0;;;41795:18;;41762:123;41853:5;-1:-1:-1;;;;;41853:15:0;;41869:3;41853:20;;;;;;;;;;;;;-1:-1:-1;;;;;41853:20:0;-1:-1:-1;;;;;41853:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41853:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;41853:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;41853:20:0;;-1:-1:-1;41846:27:0;;14035:471;14093:7;14338:6;14334:47;;-1:-1:-1;14368:1:0;14361:8;;14334:47;14405:5;;;14409:1;14405;:5;:1;14429:5;;;;;:10;14421:56;;;;-1:-1:-1;;;14421:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14974:132;15032:7;15059:39;15063:1;15066;15059:39;;;;;;;;;;;;;;;;;:3;:39::i;39706:348::-;39792:4;39813:11;39809:55;;-1:-1:-1;39848:4:0;39841:11;;39809:55;39880:12;39886:5;39880;:12::i;:::-;39876:171;;;39909:37;;-1:-1:-1;;;;;39909:29:0;;;:37;;;;;39939:6;;39909:37;;;;39939:6;39909:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39909:37:0;39876:171;;;39979:30;-1:-1:-1;;;;;39979:18:0;;39998:2;40002:6;39979:30;:18;:30;:::i;:::-;-1:-1:-1;40031:4:0;39876:171;39706:348;;;;;:::o;41138:518::-;41231:12;41237:5;41231;:12::i;:::-;41226:423;;41264:11;41260:101;;41296:24;-1:-1:-1;;;;;41296:17:0;;41314:2;41318:1;41296:24;:17;:24;:::i;:::-;41339:7;;41260:101;41397:34;;;-1:-1:-1;;;41397:34:0;;41421:4;41397:34;;;;-1:-1:-1;;;;;41397:34:0;;;;;;;;;41377:17;;41397:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;41397:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;41397:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;41397:34:0;;-1:-1:-1;41450:18:0;;;41446:192;;;41493:13;;41489:86;;41531:24;-1:-1:-1;;;;;41531:17:0;;41549:2;41553:1;41531:24;:17;:24;:::i;:::-;41593:29;-1:-1:-1;;;;;41593:17:0;;41611:2;41615:6;41593:29;:17;:29;:::i;41226:423::-;41138:518;;;:::o;150992:1252::-;151157:20;151194:17;:9;-1:-1:-1;;;;;151194:15:0;;:17::i;:::-;151190:78;;;-1:-1:-1;;;;;;;;;;;;;;;;151228:12:0;;151247:6;151228:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;151228:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151228:28:0;;;;;151190:78;151280:20;151303:17;:9;-1:-1:-1;;;;;151303:15:0;;:17::i;:::-;:36;;151330:9;151303:36;;;-1:-1:-1;;;;;;;;;;;151303:36:0;151280:59;;151350:18;151371:17;:9;-1:-1:-1;;;;;151371:15:0;;:17::i;:::-;:36;;151398:9;151371:36;;;-1:-1:-1;;;;;;;;;;;151371:36:0;151448:45;;;-1:-1:-1;;;151448:45:0;;-1:-1:-1;;;;;151448:45:0;;;;;;;;;;;;;;;151350:57;;-1:-1:-1;151418:27:0;;75639:42;;151448:17;;:45;;;;;;;;;;;;;;75639:42;151448:45;;;5:2:-1;;;;30:1;27;20:12;5:2;151448:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151448:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;151448:45:0;;-1:-1:-1;151504:13:0;;151589:54;-1:-1:-1;;;;;151589:18:0;;151608:13;151623:11;151636:6;151589:54;:18;:54;:::i;:::-;151552:91;;-1:-1:-1;151552:91:0;-1:-1:-1;151552:91:0;-1:-1:-1;151654:169:0;;;;151683:8;-1:-1:-1;;;;;151683:13:0;;:15;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;151683:15:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151683:15:0;;;;151654:169;;;151729:8;151725:98;;;151754:57;;;-1:-1:-1;;;151754:57:0;;151768:42;151754:57;;;;;;-1:-1:-1;;;;;151754:13:0;;;;;:57;;;;;-1:-1:-1;;151754:57:0;;;;;;;-1:-1:-1;151754:13:0;:57;;;5:2:-1;;;;30:1;27;20:12;5:2;151754:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151754:57:0;;;;151725:98;151835:58;-1:-1:-1;;;;;151835:31:0;;151875:8;151886:6;151835:58;:31;:58;:::i;:::-;;151958:11;-1:-1:-1;;;;;151942:29:0;151924:13;-1:-1:-1;;;;;151908:31:0;:63;151904:227;;;151988:49;;;-1:-1:-1;;;151988:49:0;;152002:1;151988:49;;;;;;;;;;;;152027:4;151988:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;151988:13:0;;;;;:49;;;;;;;;;;;152002:1;151988:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;151988:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;151988:49:0;;;;151904:227;;;152070:49;;;-1:-1:-1;;;152070:49:0;;;;;;;;152098:1;152070:49;;;;;;152109:4;152070:49;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;152070:13:0;;;;;:49;;;;;;;;;;;152098:1;152070:13;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;152070:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152070:49:0;;;;151904:227;152147:17;:9;-1:-1:-1;;;;;152147:15:0;;:17::i;:::-;152143:94;;;152195:29;;;-1:-1:-1;;;152195:29:0;;152218:4;152195:29;;;;;;-1:-1:-1;;;;;;;;;;;71848:42:0;152181:13;;71848:42;;152195:14;;:29;;;;;;;;;;;;;;71848:42;152195:29;;;5:2:-1;;;;30:1;27;20:12;5:2;152195:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152195:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;152195:29:0;152181:44;;;-1:-1:-1;;;;;;152181:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;152181:44:0;;;;;;;-1:-1:-1;152181:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;152181:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;152181:44:0;;;;152143:94;150992:1252;;;;;;;;;;;:::o;152252:457::-;152441:260;152480:8;152503:9;152527:143;152570:9;152598:8;152625:6;152650:5;152527:24;:143::i;:::-;152685:5;152441:24;:260::i;153964:944::-;154152:22;76090:42;154177:38;154238:17;-1:-1:-1;;;;;154238:15:0;;;:17::i;:::-;:36;;154265:9;154238:36;;;-1:-1:-1;;;;;;;;;;;154238:36:0;154298:17;:9;-1:-1:-1;;;;;154298:15:0;;:17::i;:::-;:36;;154325:9;154298:36;;;-1:-1:-1;;;;;;;;;;;154298:36:0;154350:9;154362:1;154350:13;154177:197;;;;;;;;;;;;;-1:-1:-1;;;;;154177:197:0;-1:-1:-1;;;;;154177:197:0;;;;;;-1:-1:-1;;;;;154177:197:0;-1:-1:-1;;;;;154177:197:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;154177:197:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154177:197:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;154177: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;154177: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;154177:197:0;;421:4:-1;412:14;;;;154177:197:0;;;;;412:14:-1;154177: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;154177:197:0;;;;;;;;;;;154152:222;;154391:17;:9;-1:-1:-1;;;;;154391:15:0;;:17::i;:::-;154387:78;;;-1:-1:-1;;;;;;;;;;;;;;;;154425:12:0;;154444:6;154425:28;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;154425:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154425:28:0;;;;;154387:78;154477:81;154533:5;154539:9;154533:16;;;;;;;;;;;;;;154551:6;154478:17;:9;-1:-1:-1;;;;;154478:15:0;;:17::i;:::-;:36;;154505:9;154478:36;;;-1:-1:-1;;;;;;;;;;;154478:36:0;-1:-1:-1;;;;;154477:55:0;;:81;;:55;:81;:::i;:::-;154583:5;154589:9;154583:16;;;;;;;;;;;;;;-1:-1:-1;;;;;154569:49:0;;154633:17;:9;-1:-1:-1;;;;;154633:15:0;;:17::i;:::-;:36;;154660:9;154633:36;;;-1:-1:-1;;;;;;;;;;;154633:36:0;154684:6;154705:17;:9;-1:-1:-1;;;;;154705:15:0;;:17::i;:::-;:36;;154732:9;154705:36;;;-1:-1:-1;;;;;;;;;;;154705:36:0;154756:1;-1:-1:-1;;154569:225:0;;;;;;;;;;;;;-1:-1:-1;;;;;154569:225:0;-1:-1:-1;;;;;154569:225:0;;;;;;;;;;;-1:-1:-1;;;;;154569:225:0;-1:-1:-1;;;;;154569:225:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;154569:225:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154569:225:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;154811:17:0;;-1:-1:-1;;;;;;154811:15:0;;;:17::i;:::-;154807:94;;;154859:29;;;-1:-1:-1;;;154859:29:0;;154882:4;154859:29;;;;;;-1:-1:-1;;;;;;;;;;;71848:42:0;154845:13;;71848:42;;154859:14;;:29;;;;;;;;;;;;;;71848:42;154859:29;;;5:2:-1;;;;30:1;27;20:12;5:2;154859:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154859:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;154859:29:0;154845:44;;;-1:-1:-1;;;;;;154845:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;154845:44:0;;;;;;;-1:-1:-1;154845:44:0;;;;5:2:-1;;;;30:1;27;20:12;147928:1737:0;148180:16;;;148194:1;148180:16;;;;;;;;;148131:6;;148150:27;;148180:16;;;;;;;105:10:-1;148180:16:0;88:34:-1;136:17;;-1:-1;148180:16:0;148150:46;;148223:9;148207:10;148218:1;148207:13;;;;;;;;;;;;;:25;;;;;148250:17;:9;-1:-1:-1;;;;;148250:15:0;;:17::i;:::-;148245:729;;148284:21;73365:42;-1:-1:-1;;;;;148308:36:0;;148363:9;148391:34;148444:10;148487:1;148473:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;148473:16:0;;148308:196;;;;;;;;;;;;;-1:-1:-1;;;;;148308:196:0;-1:-1:-1;;;;;148308: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;148308: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;148308:196:0;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;148308:196:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;148308:196:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;148308: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;148308: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;148308:196:0;;420:4:-1;411:14;;;;148308:196:0;;;;;411:14:-1;148308: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;148308:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;148308:196:0;;-1:-1:-1;148284:220:0;;-1:-1:-1;148521:62:0;;-1:-1:-1;;;;;;;148521:26:0;;73131:42;148576:6;148521:62;:26;:62;:::i;:::-;73131:42;-1:-1:-1;;;;;148613:37:0;;148669:9;148697:12;71580:42;148766:4;-1:-1:-1;;148820:1:0;148840:42;148911:3;148902:5;:12;;148918:2;148901:19;148939:8;148613:349;;;;;;;;;;;;;-1:-1:-1;;;;;148613:349:0;-1:-1:-1;;;;;148613:349:0;;;;;;;;;;;-1:-1:-1;;;;;148613:349:0;-1:-1:-1;;;;;148613:349:0;;;;;;-1:-1:-1;;;;;148613:349:0;-1:-1:-1;;;;;148613:349:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;148613:349:0;-1:-1:-1;;;;;148613:349: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;148613:349:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;148613:349:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;148613:349:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;148613:349:0;;-1:-1:-1;;148245:729:0;148991:17;:9;-1:-1:-1;;;;;148991:15:0;;:17::i;:::-;148986:672;;149025:21;73365:42;-1:-1:-1;;;;;149049:36:0;;149104:9;149132:34;149185:10;149228:1;149214:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;149214:16:0;;149049:196;;;;;;;;;;;;;-1:-1:-1;;;;;149049:196:0;-1:-1:-1;;;;;149049: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;149049: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;149049:196:0;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149049:196:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149049:196:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;149049: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;149049: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;149049:196:0;;420:4:-1;411:14;;;;149049:196:0;;;;;411:14:-1;149049: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;149049:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149025:220;;73131:42;-1:-1:-1;;;;;149277:37:0;;149321:12;71580:42;149383:12;149414:9;149450:4;-1:-1:-1;;149504:1:0;149524:42;149595:3;149586:5;:12;;149602:2;149585:19;149623:8;149277:369;;;;;;;;;;;;;-1:-1:-1;;;;;149277:369:0;-1:-1:-1;;;;;149277:369:0;;;;;;;;;;;-1:-1:-1;;;;;149277:369:0;-1:-1:-1;;;;;149277:369:0;;;;;;-1:-1:-1;;;;;149277:369:0;-1:-1:-1;;;;;149277:369:0;;;;;;;;;;;;;;;;-1:-1:-1;;;;;149277:369:0;-1:-1:-1;;;;;149277:369: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;149277:369:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149277:369:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;149277:369:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;78539:951:0;78655:7;78680:17;:9;-1:-1:-1;;;;;78680:15:0;;:17::i;:::-;78679:18;:40;;;;;78702:17;:9;-1:-1:-1;;;;;78702:15:0;;:17::i;:::-;78701:18;78679:40;78675:81;;;-1:-1:-1;78743:1:0;78736:8;;78675:81;78768:27;73242:42;78798:37;78850:17;-1:-1:-1;;;;;78850:15:0;;;:17::i;:::-;:41;;78882:9;78850:41;;;78870:9;78850:41;78798:104;;;;;;;;;;;;;-1:-1:-1;;;;;78798:104:0;-1:-1:-1;;;;;78798:104:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;78798:104:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;78798:104:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;78798: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;78798: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;78798:104:0;;421:4:-1;412:14;;;;78798:104:0;;;;;412:14:-1;78798: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;78798:104:0;;;;;;;;;;;78768:134;;78920:6;78929:1;78920:10;;78915:547;78936:10;:17;78932:1;:21;78915:547;;;79006:3;78988:10;78999:1;78988:13;;;;;;;;;;;;;;78980:22;;:29;;79014:4;78979:39;;:153;;;;;79049:10;79060:1;79049:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;79049:83:0;;;;78979:153;:270;;;;;79166:10;79177:1;79166:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;79166:83:0;;;;78979:270;:387;;;;;79283:10;79294:1;79283:13;;;;;;;;;;;;;;-1:-1:-1;;;;;;79283:83:0;;;;78979:387;78975:476;;;79422:10;79433:1;79422:13;;;;;;;;;;;;;;79415:20;;;;;;78975:476;78955:3;;78915:547;;;-1:-1:-1;79481:1:0;;78539:951;-1:-1:-1;;;;78539:951:0:o;13119:136::-;13177:7;13204:43;13208:1;13211;13204:43;;;;;;;;;;;;;;;;;:3;:43::i;36361:204::-;36488:68;;;-1:-1:-1;;;;;36488:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;36488:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;36462:95:0;;36481:5;;36462:18;:95::i;15636:345::-;15722:7;15824:12;15817:5;15809:28;;;;-1:-1:-1;;;15809: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;15809:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15848:9;15864:1;15860;:5;;;;;;;15636:345;-1:-1:-1;;;;;15636:345:0:o;36177:176::-;36286:58;;;-1:-1:-1;;;;;36286:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;36286:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;36260:85:0;;36279:5;;36260:18;:85::i;36573:621::-;36943:10;;;36942:62;;-1:-1:-1;36959:39:0;;;-1:-1:-1;;;36959:39:0;;36983:4;36959:39;;;;-1:-1:-1;;;;;36959:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;36959:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;36959:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;36959:39:0;:44;36942:62;36934:152;;;;-1:-1:-1;;;36934:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37123:62;;;-1:-1:-1;;;;;37123:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;37123:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;37097:89:0;;37116:5;;37097:18;:89::i;43460:1009::-;43625:14;;;;43702:47;-1:-1:-1;;;;;43702:28:0;;43739:8;43702:47;:28;:47;:::i;:::-;43682:67;-1:-1:-1;43760:18:0;43781:47;-1:-1:-1;;;;;43781:28:0;;43818:8;43781:47;:28;:47;:::i;:::-;43760:68;;43840:16;43858;43879:8;-1:-1:-1;;;;;43879:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43879:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43879:22:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;43879:22:0;;;;;;;;;-1:-1:-1;43879:22:0;-1:-1:-1;;;;;;43916:21:0;;;;;;;43912:97;;;43978:8;43912:97;44043:8;-1:-1:-1;;;;;44031:20:0;:9;:20;:45;;;;44068:8;-1:-1:-1;;;;;44055:21:0;:10;:21;44031:45;44019:58;;44100:8;44099:9;:60;;;;;44125:8;-1:-1:-1;;;;;44113:20:0;:9;:20;:45;;;;44150:8;-1:-1:-1;;;;;44137:21:0;:10;:21;44113:45;44088:71;-1:-1:-1;44172:23:0;44198:17;:8;44211:3;44198:17;:12;:17;:::i;:::-;44172:43;;44226:17;44246:51;44266:30;44275:10;44287:8;-1:-1:-1;;;;;44266:30:0;:8;:30::i;:::-;44246:15;;:51;:19;:51;:::i;:::-;44226:71;;44308:19;44330:60;44374:15;44330:39;44364:4;44330:29;44339:9;44350:8;-1:-1:-1;;;;;44330:29:0;:8;:29::i;:::-;:33;:39;:33;:39;:::i;:::-;:43;:60;:43;:60;:::i;:::-;44308:82;-1:-1:-1;44411:16:0;;44410:51;;44435:26;:9;44449:11;44435:26;:13;:26;:::i;:::-;44410:51;;;44431:1;44410:51;44401:60;;43460:1009;;;;;;;;;;;;;;;:::o;13592:192::-;13678:7;13714:12;13706:6;;;;13698:29;;;;-1:-1:-1;;;13698:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;13698:29:0;-1:-1:-1;;;13750:5:0;;;13592:192::o;38216:1114::-;38820:27;38828:5;-1:-1:-1;;;;;38820:25:0;;:27::i;:::-;38812:71;;;;;-1:-1:-1;;;38812:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;38957:12;38971:23;39006:5;-1:-1:-1;;;;;38998:19:0;39018:4;38998: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;;;38998: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;;38956:67:0;;;;39042:7;39034:52;;;;;-1:-1:-1;;;39034:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39103:17;;:21;39099:224;;39245:10;39234:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39234:30:0;39226:85;;;;-1:-1:-1;;;39226:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;32018:106;32076:7;32107:1;32103;:5;:13;;32115:1;32103:13;;;-1:-1:-1;32111:1:0;;32018:106;-1:-1:-1;32018:106:0:o;33206:619::-;33266:4;33734:20;;33577:66;33774:23;;;;;;:42;;-1:-1:-1;33801:15:0;;;33774:42;33766:51;33206:619;-1:-1:-1;;;;33206:619:0:o;129946:25649::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;
Swarm Source
bzzr://a7810b563a2b3b8d2c6de6f3026721a61f47df98505f5574f26361201e0559cf
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1.76
Net Worth in ETH
0.00086
Token Allocations
ANY
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BSC | 100.00% | $1.76 | 1 | $1.76 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.