Source Code
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Swap | 23044101 | 140 days ago | 0.00577308 ETH | ||||
| Transfer | 23044101 | 140 days ago | 0.00577308 ETH | ||||
| Swap | 21359696 | 375 days ago | 0.00688582 ETH | ||||
| Transfer | 21359696 | 375 days ago | 0.00688582 ETH | ||||
| - | 11153850 | 1876 days ago | 1.5 ETH | ||||
| - | 11153850 | 1876 days ago | 1.5 ETH | ||||
| - | 11134653 | 1879 days ago | 3.85 ETH | ||||
| - | 11134653 | 1879 days ago | 3.85 ETH | ||||
| - | 10953725 | 1907 days ago | 3.90809233 ETH | ||||
| - | 10953725 | 1907 days ago | 3.90809233 ETH | ||||
| - | 10951240 | 1907 days ago | 1.595 ETH | ||||
| - | 10951240 | 1907 days ago | 1.595 ETH | ||||
| - | 10834163 | 1925 days ago | 5 ETH | ||||
| - | 10834163 | 1925 days ago | 5 ETH | ||||
| - | 10786635 | 1933 days ago | 1,145 ETH | ||||
| - | 10786635 | 1933 days ago | 1,145 ETH | ||||
| - | 10747567 | 1939 days ago | 50 ETH | ||||
| - | 10747567 | 1939 days ago | 50 ETH | ||||
| - | 10747562 | 1939 days ago | 101 ETH | ||||
| - | 10747562 | 1939 days ago | 101 ETH | ||||
| - | 10747559 | 1939 days ago | 10.1 ETH | ||||
| - | 10747559 | 1939 days ago | 10.1 ETH | ||||
| - | 10747559 | 1939 days ago | 76.76 ETH | ||||
| - | 10747559 | 1939 days ago | 76.76 ETH | ||||
| - | 10747548 | 1939 days ago | 15 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OneSplitWrap
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2020-07-08
*/
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: contracts/IOneSplit.sol
pragma solidity ^0.5.0;
//
// [ msg.sender ]
// | |
// | |
// \_/
// +---------------+ ________________________________
// | OneSplitAudit | _______________________________ \
// +---------------+ \ \
// | | ______________ | | (staticcall)
// | | / ____________ \ | |
// | | (call) / / \ \ | |
// | | / / | | | |
// \_/ | | \_/ \_/
// +--------------+ | | +----------------------+
// | OneSplitWrap | | | | OneSplitViewWrap |
// +--------------+ | | +----------------------+
// | | | | | |
// | | (delegatecall) | | (staticcall) | | (staticcall)
// \_/ | | \_/
// +--------------+ | | +------------------+
// | OneSplit | | | | OneSplitView |
// +--------------+ | | +------------------+
// | | / /
// \ \________________/ /
// \__________________/
//
contract IOneSplitConsts {
// flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ...
uint256 internal constant FLAG_DISABLE_UNISWAP = 0x01;
uint256 internal constant DEPRECATED_FLAG_DISABLE_KYBER = 0x02; // Deprecated
uint256 internal constant FLAG_DISABLE_BANCOR = 0x04;
uint256 internal constant FLAG_DISABLE_OASIS = 0x08;
uint256 internal constant FLAG_DISABLE_COMPOUND = 0x10;
uint256 internal constant FLAG_DISABLE_FULCRUM = 0x20;
uint256 internal constant FLAG_DISABLE_CHAI = 0x40;
uint256 internal constant FLAG_DISABLE_AAVE = 0x80;
uint256 internal constant FLAG_DISABLE_SMART_TOKEN = 0x100;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_ETH = 0x200; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_BDAI = 0x400;
uint256 internal constant FLAG_DISABLE_IEARN = 0x800;
uint256 internal constant FLAG_DISABLE_CURVE_COMPOUND = 0x1000;
uint256 internal constant FLAG_DISABLE_CURVE_USDT = 0x2000;
uint256 internal constant FLAG_DISABLE_CURVE_Y = 0x4000;
uint256 internal constant FLAG_DISABLE_CURVE_BINANCE = 0x8000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_DAI = 0x10000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDC = 0x20000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_CURVE_SYNTHETIX = 0x40000;
uint256 internal constant FLAG_DISABLE_WETH = 0x80000;
uint256 internal constant FLAG_DISABLE_UNISWAP_COMPOUND = 0x100000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_UNISWAP_CHAI = 0x200000; // Works only when ETH<>DAI or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_UNISWAP_AAVE = 0x400000; // Works only when one of assets is ETH or FLAG_ENABLE_MULTI_PATH_ETH
uint256 internal constant FLAG_DISABLE_IDLE = 0x800000;
uint256 internal constant FLAG_DISABLE_MOONISWAP = 0x1000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2 = 0x2000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ETH = 0x4000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_DAI = 0x8000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_USDC = 0x10000000;
uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000;
uint256 internal constant FLAG_DISABLE_ALL_WRAP_SOURCES = 0x40000000;
uint256 internal constant FLAG_DISABLE_CURVE_PAX = 0x80000000;
uint256 internal constant FLAG_DISABLE_CURVE_RENBTC = 0x100000000;
uint256 internal constant FLAG_DISABLE_CURVE_TBTC = 0x200000000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_USDT = 0x400000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_WBTC = 0x800000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_TBTC = 0x1000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_RENBTC = 0x2000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_DFORCE_SWAP = 0x4000000000;
uint256 internal constant FLAG_DISABLE_SHELL = 0x8000000000;
uint256 internal constant FLAG_ENABLE_CHI_BURN = 0x10000000000;
uint256 internal constant FLAG_DISABLE_MSTABLE_MUSD = 0x20000000000;
uint256 internal constant FLAG_DISABLE_CURVE_SBTC = 0x40000000000;
uint256 internal constant FLAG_DISABLE_DMM = 0x80000000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_ALL = 0x100000000000;
uint256 internal constant FLAG_DISABLE_CURVE_ALL = 0x200000000000;
uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400000000000;
uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_ALL = 0x1000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_1 = 0x2000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_2 = 0x4000000000000;
uint256 internal constant FLAG_DISABLE_BALANCER_3 = 0x8000000000000;
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_UNISWAP_RESERVE = 0x10000000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_OASIS_RESERVE = 0x20000000000000; // Deprecated, Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_KYBER_BANCOR_RESERVE = 0x40000000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_ENABLE_REFERRAL_GAS_SPONSORSHIP = 0x80000000000000; // Turned off by default
uint256 internal constant DEPRECATED_FLAG_ENABLE_MULTI_PATH_COMP = 0x100000000000000; // Deprecated, Turned off by default
uint256 internal constant FLAG_DISABLE_KYBER_ALL = 0x200000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_1 = 0x400000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_2 = 0x800000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_3 = 0x1000000000000000;
uint256 internal constant FLAG_DISABLE_KYBER_4 = 0x2000000000000000;
uint256 internal constant FLAG_ENABLE_CHI_BURN_BY_ORIGIN = 0x4000000000000000;
}
contract IOneSplit is IOneSplitConsts {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
);
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags
)
public
payable
returns(uint256 returnAmount);
}
contract IOneSplitMulti is IOneSplit {
function getExpectedReturnWithGasMulti(
IERC20[] memory tokens,
uint256 amount,
uint256[] memory parts,
uint256[] memory flags,
uint256[] memory destTokenEthPriceTimesGasPrices
)
public
view
returns(
uint256[] memory returnAmounts,
uint256 estimateGasAmount,
uint256[] memory distribution
);
function swapMulti(
IERC20[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256[] memory flags
)
public
payable
returns(uint256 returnAmount);
}
// File: @openzeppelin/contracts/math/SafeMath.sol
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File: contracts/interface/IUniswapExchange.sol
pragma solidity ^0.5.0;
interface IUniswapExchange {
function getEthToTokenInputPrice(uint256 ethSold) external view returns (uint256 tokensBought);
function getTokenToEthInputPrice(uint256 tokensSold) external view returns (uint256 ethBought);
function ethToTokenSwapInput(uint256 minTokens, uint256 deadline)
external
payable
returns (uint256 tokensBought);
function tokenToEthSwapInput(uint256 tokensSold, uint256 minEth, uint256 deadline)
external
returns (uint256 ethBought);
function tokenToTokenSwapInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address tokenAddr
) external returns (uint256 tokensBought);
}
// File: contracts/interface/IUniswapFactory.sol
pragma solidity ^0.5.0;
interface IUniswapFactory {
function getExchange(IERC20 token) external view returns (IUniswapExchange exchange);
}
// File: contracts/interface/IKyberNetworkContract.sol
pragma solidity ^0.5.0;
interface IKyberNetworkContract {
function searchBestRate(IERC20 src, IERC20 dest, uint256 srcAmount, bool usePermissionless)
external
view
returns (address reserve, uint256 rate);
}
// File: contracts/interface/IKyberNetworkProxy.sol
pragma solidity ^0.5.0;
interface IKyberNetworkProxy {
function getExpectedRateAfterFee(
IERC20 src,
IERC20 dest,
uint256 srcQty,
uint256 platformFeeBps,
bytes calldata hint
) external view returns (uint256 expectedRate);
function tradeWithHintAndFee(
IERC20 src,
uint256 srcAmount,
IERC20 dest,
address payable destAddress,
uint256 maxDestAmount,
uint256 minConversionRate,
address payable platformWallet,
uint256 platformFeeBps,
bytes calldata hint
) external payable returns (uint256 destAmount);
function kyberNetworkContract() external view returns (IKyberNetworkContract);
// TODO: Limit usage by tx.gasPrice
// function maxGasPrice() external view returns (uint256);
// TODO: Limit usage by user cap
// function getUserCapInWei(address user) external view returns (uint256);
// function getUserCapInTokenWei(address user, IERC20 token) external view returns (uint256);
}
// File: contracts/interface/IKyberStorage.sol
pragma solidity ^0.5.0;
interface IKyberStorage {
function getReserveIdsPerTokenSrc(
IERC20 token
) external view returns (bytes32[] memory);
}
// File: contracts/interface/IKyberHintHandler.sol
pragma solidity ^0.5.0;
interface IKyberHintHandler {
enum TradeType {
BestOfAll,
MaskIn,
MaskOut,
Split
}
function buildTokenToEthHint(
IERC20 tokenSrc,
TradeType tokenToEthType,
bytes32[] calldata tokenToEthReserveIds,
uint256[] calldata tokenToEthSplits
) external view returns (bytes memory hint);
function buildEthToTokenHint(
IERC20 tokenDest,
TradeType ethToTokenType,
bytes32[] calldata ethToTokenReserveIds,
uint256[] calldata ethToTokenSplits
) external view returns (bytes memory hint);
}
// File: contracts/interface/IBancorNetwork.sol
pragma solidity ^0.5.0;
interface IBancorNetwork {
function getReturnByPath(address[] calldata path, uint256 amount)
external
view
returns (uint256 returnAmount, uint256 conversionFee);
function claimAndConvert(address[] calldata path, uint256 amount, uint256 minReturn)
external
returns (uint256);
function convert(address[] calldata path, uint256 amount, uint256 minReturn)
external
payable
returns (uint256);
}
// File: contracts/interface/IBancorContractRegistry.sol
pragma solidity ^0.5.0;
contract IBancorContractRegistry {
function addressOf(bytes32 contractName) external view returns (address);
}
// File: contracts/interface/IBancorNetworkPathFinder.sol
pragma solidity ^0.5.0;
interface IBancorNetworkPathFinder {
function generatePath(IERC20 sourceToken, IERC20 targetToken)
external
view
returns (address[] memory);
}
// File: contracts/interface/IBancorConverterRegistry.sol
pragma solidity ^0.5.0;
interface IBancorConverterRegistry {
function getConvertibleTokenSmartTokenCount(IERC20 convertibleToken)
external view returns(uint256);
function getConvertibleTokenSmartTokens(IERC20 convertibleToken)
external view returns(address[] memory);
function getConvertibleTokenSmartToken(IERC20 convertibleToken, uint256 index)
external view returns(address);
function isConvertibleTokenSmartToken(IERC20 convertibleToken, address value)
external view returns(bool);
}
// File: contracts/interface/IBancorEtherToken.sol
pragma solidity ^0.5.0;
contract IBancorEtherToken is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
// File: contracts/interface/IBancorFinder.sol
pragma solidity ^0.5.0;
interface IBancorFinder {
function buildBancorPath(
IERC20 fromToken,
IERC20 destToken
)
external
view
returns(address[] memory path);
}
// File: contracts/interface/IOasisExchange.sol
pragma solidity ^0.5.0;
interface IOasisExchange {
function getBuyAmount(IERC20 buyGem, IERC20 payGem, uint256 payAmt)
external
view
returns (uint256 fillAmt);
function sellAllAmount(IERC20 payGem, uint256 payAmt, IERC20 buyGem, uint256 minFillAmount)
external
returns (uint256 fillAmt);
}
// File: contracts/interface/IWETH.sol
pragma solidity ^0.5.0;
contract IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
// File: contracts/interface/ICurve.sol
pragma solidity ^0.5.0;
interface ICurve {
// solium-disable-next-line mixedcase
function get_dy_underlying(int128 i, int128 j, uint256 dx) external view returns(uint256 dy);
// solium-disable-next-line mixedcase
function get_dy(int128 i, int128 j, uint256 dx) external view returns(uint256 dy);
// solium-disable-next-line mixedcase
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 minDy) external;
// solium-disable-next-line mixedcase
function exchange(int128 i, int128 j, uint256 dx, uint256 minDy) external;
}
contract ICurveRegistry {
function get_pool_info(address pool)
external
view
returns(
uint256[8] memory balances,
uint256[8] memory underlying_balances,
uint256[8] memory decimals,
uint256[8] memory underlying_decimals,
address lp_token,
uint256 A,
uint256 fee
);
}
contract ICurveCalculator {
function get_dy(
int128 nCoins,
uint256[8] calldata balances,
uint256 amp,
uint256 fee,
uint256[8] calldata rates,
uint256[8] calldata precisions,
bool underlying,
int128 i,
int128 j,
uint256[100] calldata dx
) external view returns(uint256[100] memory dy);
}
// File: contracts/interface/IChai.sol
pragma solidity ^0.5.0;
interface IPot {
function dsr() external view returns (uint256);
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}
contract IChai is IERC20 {
function POT() public view returns (IPot);
function join(address dst, uint256 wad) external;
function exit(address src, uint256 wad) external;
}
library ChaiHelper {
IPot private constant POT = IPot(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7);
uint256 private constant RAY = 10**27;
function _mul(uint256 x, uint256 y) private pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function _rmul(uint256 x, uint256 y) private pure returns (uint256 z) {
// always rounds down
z = _mul(x, y) / RAY;
}
function _rdiv(uint256 x, uint256 y) private pure returns (uint256 z) {
// always rounds down
z = _mul(x, RAY) / y;
}
function rpow(uint256 x, uint256 n, uint256 base) private pure returns (uint256 z) {
// solium-disable-next-line security/no-inline-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
z := base
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := base
}
default {
z := x
}
let half := div(base, 2) // for rounding.
for {
n := div(n, 2)
} n {
n := div(n, 2)
} {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) {
revert(0, 0)
}
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, base)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) {
revert(0, 0)
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, base)
}
}
}
}
}
function potDrip() private view returns (uint256) {
return _rmul(rpow(POT.dsr(), now - POT.rho(), RAY), POT.chi());
}
function chaiPrice(IChai chai) internal view returns(uint256) {
return chaiToDai(chai, 1e18);
}
function daiToChai(
IChai /*chai*/,
uint256 amount
) internal view returns (uint256) {
uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi();
return _rdiv(amount, chi);
}
function chaiToDai(
IChai /*chai*/,
uint256 amount
) internal view returns (uint256) {
uint256 chi = (now > POT.rho()) ? potDrip() : POT.chi();
return _rmul(chi, amount);
}
}
// File: contracts/interface/ICompound.sol
pragma solidity ^0.5.0;
contract ICompound {
function markets(address cToken)
external
view
returns (bool isListed, uint256 collateralFactorMantissa);
}
contract ICompoundToken is IERC20 {
function underlying() external view returns (address);
function exchangeRateStored() external view returns (uint256);
function mint(uint256 mintAmount) external returns (uint256);
function redeem(uint256 redeemTokens) external returns (uint256);
}
contract ICompoundEther is IERC20 {
function mint() external payable;
function redeem(uint256 redeemTokens) external returns (uint256);
}
// File: contracts/interface/ICompoundRegistry.sol
pragma solidity ^0.5.0;
contract ICompoundRegistry {
function tokenByCToken(ICompoundToken cToken) external view returns(IERC20);
function cTokenByToken(IERC20 token) external view returns(ICompoundToken);
}
// File: contracts/interface/IAaveToken.sol
pragma solidity ^0.5.0;
contract IAaveToken is IERC20 {
function underlyingAssetAddress() external view returns (IERC20);
function redeem(uint256 amount) external;
}
interface IAaveLendingPool {
function core() external view returns (address);
function deposit(IERC20 token, uint256 amount, uint16 refCode) external payable;
}
// File: contracts/interface/IAaveRegistry.sol
pragma solidity ^0.5.0;
contract IAaveRegistry {
function tokenByAToken(IAaveToken aToken) external view returns(IERC20);
function aTokenByToken(IERC20 token) external view returns(IAaveToken);
}
// File: contracts/interface/IMooniswap.sol
pragma solidity ^0.5.0;
interface IMooniswapRegistry {
function target() external view returns(IMooniswap);
}
interface IMooniswap {
function getReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount
)
external
view
returns(uint256 returnAmount);
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn
)
external
payable
returns(uint256 returnAmount);
}
// File: @openzeppelin/contracts/utils/Address.sol
pragma solidity ^0.5.5;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
pragma solidity ^0.5.0;
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// File: contracts/UniversalERC20.sol
pragma solidity ^0.5.0;
library UniversalERC20 {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 private constant ZERO_ADDRESS = IERC20(0x0000000000000000000000000000000000000000);
IERC20 private constant ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function universalTransfer(IERC20 token, address to, uint256 amount) internal returns(bool) {
if (amount == 0) {
return true;
}
if (isETH(token)) {
address(uint160(to)).transfer(amount);
} else {
token.safeTransfer(to, amount);
return true;
}
}
function universalTransferFrom(IERC20 token, address from, address to, uint256 amount) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()");
if (to != address(this)) {
address(uint160(to)).transfer(amount);
}
if (msg.value > amount) {
msg.sender.transfer(msg.value.sub(amount));
}
} else {
token.safeTransferFrom(from, to, amount);
}
}
function universalTransferFromSenderToThis(IERC20 token, uint256 amount) internal {
if (amount == 0) {
return;
}
if (isETH(token)) {
if (msg.value > amount) {
// Return remainder if exist
msg.sender.transfer(msg.value.sub(amount));
}
} else {
token.safeTransferFrom(msg.sender, address(this), amount);
}
}
function universalApprove(IERC20 token, address to, uint256 amount) internal {
if (!isETH(token)) {
if (amount == 0) {
token.safeApprove(to, 0);
return;
}
uint256 allowance = token.allowance(address(this), to);
if (allowance < amount) {
if (allowance > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, amount);
}
}
}
function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) {
if (isETH(token)) {
return who.balance;
} else {
return token.balanceOf(who);
}
}
function universalDecimals(IERC20 token) internal view returns (uint256) {
if (isETH(token)) {
return 18;
}
(bool success, bytes memory data) = address(token).staticcall.gas(10000)(
abi.encodeWithSignature("decimals()")
);
if (!success || data.length == 0) {
(success, data) = address(token).staticcall.gas(10000)(
abi.encodeWithSignature("DECIMALS()")
);
}
return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18;
}
function isETH(IERC20 token) internal pure returns(bool) {
return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS));
}
function notExist(IERC20 token) internal pure returns(bool) {
return (address(token) == address(-1));
}
}
// File: contracts/interface/IUniswapV2Exchange.sol
pragma solidity ^0.5.0;
interface IUniswapV2Exchange {
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}
library UniswapV2ExchangeLib {
using SafeMath for uint256;
using UniversalERC20 for IERC20;
function getReturn(
IUniswapV2Exchange exchange,
IERC20 fromToken,
IERC20 destToken,
uint amountIn
) internal view returns (uint256) {
uint256 reserveIn = fromToken.universalBalanceOf(address(exchange));
uint256 reserveOut = destToken.universalBalanceOf(address(exchange));
uint256 amountInWithFee = amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(reserveOut);
uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
return (denominator == 0) ? 0 : numerator.div(denominator);
}
}
// File: contracts/interface/IUniswapV2Factory.sol
pragma solidity ^0.5.0;
interface IUniswapV2Factory {
function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapV2Exchange pair);
}
// File: contracts/interface/IDForceSwap.sol
pragma solidity ^0.5.0;
interface IDForceSwap {
function getAmountByInput(IERC20 input, IERC20 output, uint256 amount) external view returns(uint256);
function swap(IERC20 input, IERC20 output, uint256 amount) external;
}
// File: contracts/interface/IShell.sol
pragma solidity ^0.5.0;
interface IShell {
function viewOriginTrade(
address origin,
address target,
uint256 originAmount
) external view returns (uint256);
function swapByOrigin(
address origin,
address target,
uint256 originAmount,
uint256 minTargetAmount,
uint256 deadline
) external returns (uint256);
}
// File: contracts/interface/IMStable.sol
pragma solidity ^0.5.0;
contract IMStable is IERC20 {
function getSwapOutput(
IERC20 _input,
IERC20 _output,
uint256 _quantity
)
external
view
returns (bool, string memory, uint256 output);
function swap(
IERC20 _input,
IERC20 _output,
uint256 _quantity,
address _recipient
)
external
returns (uint256 output);
function redeem(
IERC20 _basset,
uint256 _bassetQuantity
)
external
returns (uint256 massetRedeemed);
}
interface IMassetRedemptionValidator {
function getRedeemValidity(
IERC20 _mAsset,
uint256 _mAssetQuantity,
IERC20 _outputBasset
)
external
view
returns (bool, string memory, uint256 output);
}
// File: contracts/interface/IBalancerRegistry.sol
pragma solidity ^0.5.0;
interface IBalancerPool {
function swapExactAmountIn(
IERC20 tokenIn,
uint256 tokenAmountIn,
IERC20 tokenOut,
uint256 minAmountOut,
uint256 maxPrice
)
external
returns (uint256 tokenAmountOut, uint256 spotPriceAfter);
}
pragma solidity ^0.5.0;
interface IBalancerRegistry {
event PoolAdded(
address indexed pool
);
event PoolTokenPairAdded(
address indexed pool,
address indexed fromToken,
address indexed destToken
);
event IndicesUpdated(
address indexed fromToken,
address indexed destToken,
bytes32 oldIndices,
bytes32 newIndices
);
// Get info about pool pair for 1 SLOAD
function getPairInfo(address pool, address fromToken, address destToken)
external view returns(uint256 weight1, uint256 weight2, uint256 swapFee);
// Pools
function checkAddedPools(address pool)
external view returns(bool);
function getAddedPoolsLength()
external view returns(uint256);
function getAddedPools()
external view returns(address[] memory);
function getAddedPoolsWithLimit(uint256 offset, uint256 limit)
external view returns(address[] memory result);
// Tokens
function getAllTokensLength()
external view returns(uint256);
function getAllTokens()
external view returns(address[] memory);
function getAllTokensWithLimit(uint256 offset, uint256 limit)
external view returns(address[] memory result);
// Pairs
function getPoolsLength(address fromToken, address destToken)
external view returns(uint256);
function getPools(address fromToken, address destToken)
external view returns(address[] memory);
function getPoolsWithLimit(address fromToken, address destToken, uint256 offset, uint256 limit)
external view returns(address[] memory result);
function getBestPools(address fromToken, address destToken)
external view returns(address[] memory pools);
function getBestPoolsWithLimit(address fromToken, address destToken, uint256 limit)
external view returns(address[] memory pools);
// Get swap rates
function getPoolReturn(address pool, address fromToken, address destToken, uint256 amount)
external view returns(uint256);
function getPoolReturns(address pool, address fromToken, address destToken, uint256[] calldata amounts)
external view returns(uint256[] memory result);
// Add and update registry
function addPool(address pool) external returns(uint256 listed);
function addPools(address[] calldata pools) external returns(uint256[] memory listed);
function updatedIndices(address[] calldata tokens, uint256 lengthLimit) external;
}
// File: contracts/OneSplitBase.sol
pragma solidity ^0.5.0;
contract IOneSplitView is IOneSplitConsts {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
);
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
}
library DisableFlags {
function check(uint256 flags, uint256 flag) internal pure returns(bool) {
return (flags & flag) != 0;
}
}
contract OneSplitRoot is IOneSplitView {
using SafeMath for uint256;
using DisableFlags for uint256;
using UniversalERC20 for IERC20;
using UniversalERC20 for IWETH;
using UniswapV2ExchangeLib for IUniswapV2Exchange;
using ChaiHelper for IChai;
uint256 constant internal DEXES_COUNT = 31;
IERC20 constant internal ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
IBancorEtherToken constant internal bancorEtherToken = IBancorEtherToken(0xc0829421C1d260BD3cB3E0F06cfE2D52db2cE315);
IWETH constant internal weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IChai constant internal chai = IChai(0x06AF07097C9Eeb7fD685c692751D5C66dB49c215);
IERC20 constant internal dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
IERC20 constant internal usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
IERC20 constant internal usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
IERC20 constant internal tusd = IERC20(0x0000000000085d4780B73119b644AE5ecd22b376);
IERC20 constant internal busd = IERC20(0x4Fabb145d64652a948d72533023f6E7A623C7C53);
IERC20 constant internal susd = IERC20(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51);
IERC20 constant internal pax = IERC20(0x8E870D67F660D95d5be530380D0eC0bd388289E1);
IERC20 constant internal renbtc = IERC20(0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D);
IERC20 constant internal wbtc = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
IERC20 constant internal tbtc = IERC20(0x1bBE271d15Bb64dF0bc6CD28Df9Ff322F2eBD847);
IERC20 constant internal hbtc = IERC20(0x0316EB71485b0Ab14103307bf65a021042c6d380);
IERC20 constant internal sbtc = IERC20(0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6);
IKyberNetworkProxy constant internal kyberNetworkProxy = IKyberNetworkProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e);
IKyberStorage constant internal kyberStorage = IKyberStorage(0xC8fb12402cB16970F3C5F4b48Ff68Eb9D1289301);
IKyberHintHandler constant internal kyberHintHandler = IKyberHintHandler(0xa1C0Fa73c39CFBcC11ec9Eb1Afc665aba9996E2C);
IUniswapFactory constant internal uniswapFactory = IUniswapFactory(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95);
IBancorContractRegistry constant internal bancorContractRegistry = IBancorContractRegistry(0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4);
IBancorNetworkPathFinder constant internal bancorNetworkPathFinder = IBancorNetworkPathFinder(0x6F0cD8C4f6F06eAB664C7E3031909452b4B72861);
//IBancorConverterRegistry constant internal bancorConverterRegistry = IBancorConverterRegistry(0xf6E2D7F616B67E46D708e4410746E9AAb3a4C518);
IBancorFinder constant internal bancorFinder = IBancorFinder(0x2B344e14dc2641D11D338C053C908c7A7D4c30B9);
IOasisExchange constant internal oasisExchange = IOasisExchange(0x794e6e91555438aFc3ccF1c5076A74F42133d08D);
ICurve constant internal curveCompound = ICurve(0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56);
ICurve constant internal curveUSDT = ICurve(0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C);
ICurve constant internal curveY = ICurve(0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51);
ICurve constant internal curveBinance = ICurve(0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27);
ICurve constant internal curveSynthetix = ICurve(0xA5407eAE9Ba41422680e2e00537571bcC53efBfD);
ICurve constant internal curvePAX = ICurve(0x06364f10B501e868329afBc005b3492902d6C763);
ICurve constant internal curveRenBTC = ICurve(0x93054188d876f558f4a66B2EF1d97d16eDf0895B);
ICurve constant internal curveTBTC = ICurve(0x9726e9314eF1b96E45f40056bEd61A088897313E);
ICurve constant internal curveSBTC = ICurve(0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714);
IShell constant internal shell = IShell(0xA8253a440Be331dC4a7395B73948cCa6F19Dc97D);
IAaveLendingPool constant internal aave = IAaveLendingPool(0x398eC7346DcD622eDc5ae82352F02bE94C62d119);
ICompound constant internal compound = ICompound(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B);
ICompoundEther constant internal cETH = ICompoundEther(0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5);
IMooniswapRegistry constant internal mooniswapRegistry = IMooniswapRegistry(0x7079E8517594e5b21d2B9a0D17cb33F5FE2bca70);
IUniswapV2Factory constant internal uniswapV2 = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
IDForceSwap constant internal dforceSwap = IDForceSwap(0x03eF3f37856bD08eb47E2dE7ABc4Ddd2c19B60F2);
IMStable constant internal musd = IMStable(0xe2f2a5C287993345a840Db3B0845fbC70f5935a5);
IMassetRedemptionValidator constant internal musd_helper = IMassetRedemptionValidator(0x4c5e03065bC52cCe84F3ac94DF14bbAC27eac89b);
IBalancerRegistry constant internal balancerRegistry = IBalancerRegistry(0x65e67cbc342712DF67494ACEfc06fe951EE93982);
ICurveCalculator constant internal curveCalculator = ICurveCalculator(0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E);
ICurveRegistry constant internal curveRegistry = ICurveRegistry(0x7002B727Ef8F5571Cb5F9D70D13DBEEb4dFAe9d1);
ICompoundRegistry constant internal compoundRegistry = ICompoundRegistry(0xF451Dbd7Ba14BFa7B1B78A766D3Ed438F79EE1D1);
IAaveRegistry constant internal aaveRegistry = IAaveRegistry(0xEd8b133B7B88366E01Bb9E38305Ab11c26521494);
int256 internal constant VERY_NEGATIVE_VALUE = -1e72;
function _findBestDistribution(
uint256 s, // parts
int256[][] memory amounts // exchangesReturns
)
internal
pure
returns(
int256 returnAmount,
uint256[] memory distribution
)
{
uint256 n = amounts.length;
int256[][] memory answer = new int256[][](n); // int[n][s+1]
uint256[][] memory parent = new uint256[][](n); // int[n][s+1]
for (uint i = 0; i < n; i++) {
answer[i] = new int256[](s + 1);
parent[i] = new uint256[](s + 1);
}
for (uint j = 0; j <= s; j++) {
answer[0][j] = amounts[0][j];
for (uint i = 1; i < n; i++) {
answer[i][j] = -1e72;
}
parent[0][j] = 0;
}
for (uint i = 1; i < n; i++) {
for (uint j = 0; j <= s; j++) {
answer[i][j] = answer[i - 1][j];
parent[i][j] = j;
for (uint k = 1; k <= j; k++) {
if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) {
answer[i][j] = answer[i - 1][j - k] + amounts[i][k];
parent[i][j] = j - k;
}
}
}
}
distribution = new uint256[](DEXES_COUNT);
uint256 partsLeft = s;
for (uint curExchange = n - 1; partsLeft > 0; curExchange--) {
distribution[curExchange] = partsLeft - parent[curExchange][partsLeft];
partsLeft = parent[curExchange][partsLeft];
}
returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? 0 : answer[n - 1][s];
}
function _kyberReserveIdByTokens(
IERC20 fromToken,
IERC20 destToken
) internal view returns(bytes32) {
if (!fromToken.isETH() && !destToken.isETH()) {
return 0;
}
bytes32[] memory reserveIds = kyberStorage.getReserveIdsPerTokenSrc(
fromToken.isETH() ? destToken : fromToken
);
for (uint i = 0; i < reserveIds.length; i++) {
if ((uint256(reserveIds[i]) >> 248) != 0xBB && // Bridge
reserveIds[i] != 0xff4b796265722046707200000000000000000000000000000000000000000000 && // Reserve 1
reserveIds[i] != 0xffabcd0000000000000000000000000000000000000000000000000000000000 && // Reserve 2
reserveIds[i] != 0xff4f6e65426974205175616e7400000000000000000000000000000000000000) // Reserve 3
{
return reserveIds[i];
}
}
return 0;
}
function _scaleDestTokenEthPriceTimesGasPrice(
IERC20 fromToken,
IERC20 destToken,
uint256 destTokenEthPriceTimesGasPrice
) internal view returns(uint256) {
if (fromToken == destToken) {
return destTokenEthPriceTimesGasPrice;
}
uint256 mul = _cheapGetPrice(ETH_ADDRESS, destToken, 0.01 ether);
uint256 div = _cheapGetPrice(ETH_ADDRESS, fromToken, 0.01 ether);
if (div > 0) {
return destTokenEthPriceTimesGasPrice.mul(mul).div(div);
}
return 0;
}
function _cheapGetPrice(
IERC20 fromToken,
IERC20 destToken,
uint256 amount
) internal view returns(uint256 returnAmount) {
(returnAmount,,) = this.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
1,
FLAG_DISABLE_SPLIT_RECALCULATION |
FLAG_DISABLE_ALL_SPLIT_SOURCES |
FLAG_DISABLE_UNISWAP_V2_ALL |
FLAG_DISABLE_UNISWAP,
0
);
}
function _linearInterpolation(
uint256 value,
uint256 parts
) internal pure returns(uint256[] memory rets) {
rets = new uint256[](parts);
for (uint i = 0; i < parts; i++) {
rets[i] = value.mul(i + 1).div(parts);
}
}
function _tokensEqual(IERC20 tokenA, IERC20 tokenB) internal pure returns(bool) {
return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB);
}
}
contract OneSplitViewWrapBase is IOneSplitView, OneSplitRoot {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = this.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _getExpectedReturnRespectingGasFloor(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _getExpectedReturnRespectingGasFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
);
}
contract OneSplitView is IOneSplitView, OneSplitRoot {
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags // See constants in IOneSplit.sol
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
distribution = new uint256[](DEXES_COUNT);
if (fromToken == destToken) {
return (amount, 0, distribution);
}
function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory reserves = _getAllReserves(flags);
int256[][] memory matrix = new int256[][](DEXES_COUNT);
uint256[DEXES_COUNT] memory gases;
bool atLeastOnePositive = false;
for (uint i = 0; i < DEXES_COUNT; i++) {
uint256[] memory rets;
(rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts, flags);
// Prepend zero and sub gas
int256 gas = int256(gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18));
matrix[i] = new int256[](parts + 1);
for (uint j = 0; j < parts; j++) {
matrix[i][j + 1] = int256(rets[j]) - gas;
atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0);
}
}
if (!atLeastOnePositive) {
for (uint i = 0; i < DEXES_COUNT; i++) {
for (uint j = 1; j < parts + 1; j++) {
if (matrix[i][j] == 0) {
matrix[i][j] = VERY_NEGATIVE_VALUE;
}
}
}
}
(, distribution) = _findBestDistribution(parts, matrix);
(returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution(
Args({
fromToken: fromToken,
destToken: destToken,
amount: amount,
parts: parts,
flags: flags,
destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice,
distribution: distribution,
matrix: matrix,
gases: gases,
reserves: reserves
})
);
return (returnAmount, estimateGasAmount, distribution);
}
struct Args {
IERC20 fromToken;
IERC20 destToken;
uint256 amount;
uint256 parts;
uint256 flags;
uint256 destTokenEthPriceTimesGasPrice;
uint256[] distribution;
int256[][] matrix;
uint256[DEXES_COUNT] gases;
function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] reserves;
}
function _getReturnAndGasByDistribution(
Args memory args
) internal view returns(uint256 returnAmount, uint256 estimateGasAmount) {
bool[DEXES_COUNT] memory exact = [
true, // "Uniswap",
false, // "Kyber",
false, // "Bancor",
false, // "Oasis",
true, // "Curve Compound",
true, // "Curve USDT",
true, // "Curve Y",
true, // "Curve Binance",
true, // "Curve Synthetix",
true, // "Uniswap Compound",
true, // "Uniswap CHAI",
true, // "Uniswap Aave",
false, // "Mooniswap",
true, // "Uniswap V2",
true, // "Uniswap V2 (ETH)",
true, // "Uniswap V2 (DAI)",
true, // "Uniswap V2 (USDC)",
true, // "Curve Pax",
true, // "Curve RenBTC",
true, // "Curve tBTC",
true, // "Dforce XSwap",
false, // "Shell",
true, // "mStable",
true, // "Curve sBTC"
true, // "Balancer 1"
true, // "Balancer 2"
true, // "Balancer 3"
true, // "Kyber 1"
true, // "Kyber 2"
true, // "Kyber 3"
true // "Kyber 4"
];
for (uint i = 0; i < DEXES_COUNT; i++) {
if (args.distribution[i] > 0) {
if (args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION)) {
estimateGasAmount = estimateGasAmount.add(args.gases[i]);
int256 value = args.matrix[i][args.distribution[i]];
returnAmount = returnAmount.add(uint256(
(value == VERY_NEGATIVE_VALUE ? 0 : value) +
int256(args.gases[i].mul(args.destTokenEthPriceTimesGasPrice).div(1e18))
));
}
else {
(uint256[] memory rets, uint256 gas) = args.reserves[i](args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1, args.flags);
estimateGasAmount = estimateGasAmount.add(gas);
returnAmount = returnAmount.add(rets[0]);
}
}
}
}
function _getAllReserves(uint256 flags)
internal
pure
returns(function(IERC20,IERC20,uint256,uint256,uint256) view returns(uint256[] memory, uint256)[DEXES_COUNT] memory)
{
bool invert = flags.check(FLAG_DISABLE_ALL_SPLIT_SOURCES);
return [
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP) ? _calculateNoReturn : calculateUniswap,
_calculateNoReturn, // invert != flags.check(FLAG_DISABLE_KYBER) ? _calculateNoReturn : calculateKyber,
invert != flags.check(FLAG_DISABLE_BANCOR) ? _calculateNoReturn : calculateBancor,
invert != flags.check(FLAG_DISABLE_OASIS) ? _calculateNoReturn : calculateOasis,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_COMPOUND) ? _calculateNoReturn : calculateCurveCompound,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_USDT) ? _calculateNoReturn : calculateCurveUSDT,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_Y) ? _calculateNoReturn : calculateCurveY,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_BINANCE) ? _calculateNoReturn : calculateCurveBinance,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SYNTHETIX) ? _calculateNoReturn : calculateCurveSynthetix,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_COMPOUND) ? _calculateNoReturn : calculateUniswapCompound,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_CHAI) ? _calculateNoReturn : calculateUniswapChai,
invert != flags.check(FLAG_DISABLE_UNISWAP_ALL | FLAG_DISABLE_UNISWAP_AAVE) ? _calculateNoReturn : calculateUniswapAave,
invert != flags.check(FLAG_DISABLE_MOONISWAP) ? _calculateNoReturn : calculateMooniswap,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2) ? _calculateNoReturn : calculateUniswapV2,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_ETH) ? _calculateNoReturn : calculateUniswapV2ETH,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_DAI) ? _calculateNoReturn : calculateUniswapV2DAI,
invert != flags.check(FLAG_DISABLE_UNISWAP_V2_ALL | FLAG_DISABLE_UNISWAP_V2_USDC) ? _calculateNoReturn : calculateUniswapV2USDC,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_PAX) ? _calculateNoReturn : calculateCurvePAX,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_RENBTC) ? _calculateNoReturn : calculateCurveRenBTC,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_TBTC) ? _calculateNoReturn : calculateCurveTBTC,
invert != flags.check(FLAG_DISABLE_DFORCE_SWAP) ? _calculateNoReturn : calculateDforceSwap,
invert != flags.check(FLAG_DISABLE_SHELL) ? _calculateNoReturn : calculateShell,
invert != flags.check(FLAG_DISABLE_MSTABLE_MUSD) ? _calculateNoReturn : calculateMStableMUSD,
invert != flags.check(FLAG_DISABLE_CURVE_ALL | FLAG_DISABLE_CURVE_SBTC) ? _calculateNoReturn : calculateCurveSBTC,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_1) ? _calculateNoReturn : calculateBalancer1,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_2) ? _calculateNoReturn : calculateBalancer2,
invert != flags.check(FLAG_DISABLE_BALANCER_ALL | FLAG_DISABLE_BALANCER_3) ? _calculateNoReturn : calculateBalancer3,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_1) ? _calculateNoReturn : calculateKyber1,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_2) ? _calculateNoReturn : calculateKyber2,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_3) ? _calculateNoReturn : calculateKyber3,
invert != flags.check(FLAG_DISABLE_KYBER_ALL | FLAG_DISABLE_KYBER_4) ? _calculateNoReturn : calculateKyber4
];
}
function _calculateNoGas(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 /*parts*/,
uint256 /*destTokenEthPriceTimesGasPrice*/,
uint256 /*flags*/,
uint256 /*destTokenEthPrice*/
) internal view returns(uint256[] memory /*rets*/, uint256 /*gas*/) {
this;
}
// View Helpers
function _calculateBalancer(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/,
uint256 poolIndex
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](parts);
address[] memory pools = balancerRegistry.getBestPoolsWithLimit(
address(fromToken.isETH() ? weth : fromToken),
address(destToken.isETH() ? weth : destToken),
poolIndex + 1
);
if (poolIndex >= pools.length) {
return (rets, 0);
}
(bool success, bytes memory result) = address(balancerRegistry).staticcall(
abi.encodeWithSelector(
balancerRegistry.getPoolReturns.selector,
pools[poolIndex],
address(fromToken.isETH() ? weth : fromToken),
address(destToken.isETH() ? weth : destToken),
_linearInterpolation(amount, parts)
)
);
if (!success || result.length == 0) {
return (rets, 0);
}
return (
abi.decode(result, (uint256[])),
100_000
);
}
function calculateBalancer1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function calculateBalancer2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
flags,
1
);
}
function calculateBalancer3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateBalancer(
fromToken,
destToken,
amount,
parts,
flags,
2
);
}
function calculateMStableMUSD(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](parts);
if ((fromToken != usdc && fromToken != dai && fromToken != usdt && fromToken != tusd) ||
(destToken != usdc && destToken != dai && destToken != usdt && destToken != tusd))
{
return (rets, 0);
}
for (uint i = 1; i <= parts; i *= 2) {
(bool success, bytes memory data) = address(musd).staticcall(abi.encodeWithSelector(
musd.getSwapOutput.selector,
fromToken,
destToken,
amount.mul(parts.div(i)).div(parts)
));
if (success && data.length > 0) {
(,, uint256 maxRet) = abi.decode(data, (bool,string,uint256));
if (maxRet > 0) {
for (uint j = 0; j < parts.div(i); j++) {
rets[j] = maxRet.mul(j + 1).div(parts.div(i));
}
break;
}
}
}
return (
rets,
700_000
);
}
function _getCurvePoolInfo(
ICurve curve,
bool haveUnderlying
) internal view returns(
uint256[8] memory balances,
uint256[8] memory precisions,
uint256[8] memory rates,
uint256 amp,
uint256 fee
) {
uint256[8] memory underlying_balances;
uint256[8] memory decimals;
uint256[8] memory underlying_decimals;
(
balances,
underlying_balances,
decimals,
underlying_decimals,
/*address lp_token*/,
amp,
fee
) = curveRegistry.get_pool_info(address(curve));
for (uint k = 0; k < 8 && balances[k] > 0; k++) {
precisions[k] = 10 ** (18 - (haveUnderlying ? underlying_decimals : decimals)[k]);
if (haveUnderlying) {
rates[k] = underlying_balances[k].mul(1e18).div(balances[k]);
} else {
rates[k] = 1e18;
}
}
}
function _calculateCurveSelector(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
ICurve curve,
bool haveUnderlying,
IERC20[] memory tokens
) internal view returns(uint256[] memory rets) {
rets = new uint256[](parts);
int128 i = 0;
int128 j = 0;
for (uint t = 0; t < tokens.length; t++) {
if (fromToken == tokens[t]) {
i = int128(t + 1);
}
if (destToken == tokens[t]) {
j = int128(t + 1);
}
}
if (i == 0 || j == 0) {
return rets;
}
bytes memory data = abi.encodePacked(
uint256(haveUnderlying ? 1 : 0),
uint256(i - 1),
uint256(j - 1),
_linearInterpolation100(amount, parts)
);
(
uint256[8] memory balances,
uint256[8] memory precisions,
uint256[8] memory rates,
uint256 amp,
uint256 fee
) = _getCurvePoolInfo(curve, haveUnderlying);
bool success;
(success, data) = address(curveCalculator).staticcall(
abi.encodePacked(
abi.encodeWithSelector(
curveCalculator.get_dy.selector,
tokens.length,
balances,
amp,
fee,
rates,
precisions
),
data
)
);
if (!success || data.length == 0) {
return rets;
}
uint256[100] memory dy = abi.decode(data, (uint256[100]));
for (uint t = 0; t < parts; t++) {
rets[t] = dy[t];
}
}
function _linearInterpolation100(
uint256 value,
uint256 parts
) internal pure returns(uint256[100] memory rets) {
for (uint i = 0; i < parts; i++) {
rets[i] = value.mul(i + 1).div(parts);
}
}
function calculateCurveCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](2);
tokens[0] = dai;
tokens[1] = usdc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveCompound,
true,
tokens
), 720_000);
}
function calculateCurveUSDT(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveUSDT,
true,
tokens
), 720_000);
}
function calculateCurveY(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = tusd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveY,
true,
tokens
), 1_400_000);
}
function calculateCurveBinance(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = busd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveBinance,
true,
tokens
), 1_400_000);
}
function calculateCurveSynthetix(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = susd;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveSynthetix,
true,
tokens
), 200_000);
}
function calculateCurvePAX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](4);
tokens[0] = dai;
tokens[1] = usdc;
tokens[2] = usdt;
tokens[3] = pax;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curvePAX,
true,
tokens
), 1_000_000);
}
function calculateCurveRenBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](2);
tokens[0] = renbtc;
tokens[1] = wbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveRenBTC,
false,
tokens
), 130_000);
}
function calculateCurveTBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = tbtc;
tokens[1] = wbtc;
tokens[2] = hbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveTBTC,
false,
tokens
), 145_000);
}
function calculateCurveSBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = renbtc;
tokens[1] = wbtc;
tokens[2] = sbtc;
return (_calculateCurveSelector(
fromToken,
destToken,
amount,
parts,
curveSBTC,
false,
tokens
), 150_000);
}
function calculateShell(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
(bool success, bytes memory data) = address(shell).staticcall(abi.encodeWithSelector(
shell.viewOriginTrade.selector,
fromToken,
destToken,
amount
));
if (!success || data.length == 0) {
return (new uint256[](parts), 0);
}
uint256 maxRet = abi.decode(data, (uint256));
return (_linearInterpolation(maxRet, parts), 300_000);
}
function calculateDforceSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
(bool success, bytes memory data) = address(dforceSwap).staticcall(
abi.encodeWithSelector(
dforceSwap.getAmountByInput.selector,
fromToken,
destToken,
amount
)
);
if (!success || data.length == 0) {
return (new uint256[](parts), 0);
}
uint256 maxRet = abi.decode(data, (uint256));
uint256 available = destToken.universalBalanceOf(address(dforceSwap));
if (maxRet > available) {
return (new uint256[](parts), 0);
}
return (_linearInterpolation(maxRet, parts), 160_000);
}
function _calculateUniswapFormula(uint256 fromBalance, uint256 toBalance, uint256 amount) internal pure returns(uint256) {
if (amount == 0) {
return 0;
}
return amount.mul(toBalance).mul(997).div(
fromBalance.mul(1000).add(amount.mul(997))
);
}
function _calculateUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256[] memory amounts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = amounts;
if (!fromToken.isETH()) {
IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken);
if (fromExchange == IUniswapExchange(0)) {
return (new uint256[](rets.length), 0);
}
uint256 fromTokenBalance = fromToken.universalBalanceOf(address(fromExchange));
uint256 fromEtherBalance = address(fromExchange).balance;
for (uint i = 0; i < rets.length; i++) {
rets[i] = _calculateUniswapFormula(fromTokenBalance, fromEtherBalance, rets[i]);
}
}
if (!destToken.isETH()) {
IUniswapExchange toExchange = uniswapFactory.getExchange(destToken);
if (toExchange == IUniswapExchange(0)) {
return (new uint256[](rets.length), 0);
}
uint256 toEtherBalance = address(toExchange).balance;
uint256 toTokenBalance = destToken.universalBalanceOf(address(toExchange));
for (uint i = 0; i < rets.length; i++) {
rets[i] = _calculateUniswapFormula(toEtherBalance, toTokenBalance, rets[i]);
}
}
return (rets, fromToken.isETH() || destToken.isETH() ? 60_000 : 100_000);
}
function calculateUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateUniswap(
fromToken,
destToken,
_linearInterpolation(amount, parts),
flags
);
}
function _calculateUniswapWrapped(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 midTokenPrice,
uint256 flags,
uint256 gas1,
uint256 gas2
) internal view returns(uint256[] memory rets, uint256 gas) {
if (!fromToken.isETH() && destToken.isETH()) {
(rets, gas) = _calculateUniswap(
midToken,
destToken,
_linearInterpolation(amount.mul(1e18).div(midTokenPrice), parts),
flags
);
return (rets, gas + gas1);
}
else if (fromToken.isETH() && !destToken.isETH()) {
(rets, gas) = _calculateUniswap(
fromToken,
midToken,
_linearInterpolation(amount, parts),
flags
);
for (uint i = 0; i < parts; i++) {
rets[i] = rets[i].mul(midTokenPrice).div(1e18);
}
return (rets, gas + gas2);
}
return (new uint256[](parts), 0);
}
function calculateUniswapCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20 midPreToken;
if (!fromToken.isETH() && destToken.isETH()) {
midPreToken = fromToken;
}
else if (!destToken.isETH() && fromToken.isETH()) {
midPreToken = destToken;
}
if (!midPreToken.isETH()) {
ICompoundToken midToken = compoundRegistry.cTokenByToken(midPreToken);
if (midToken != ICompoundToken(0)) {
return _calculateUniswapWrapped(
fromToken,
midToken,
destToken,
amount,
parts,
midToken.exchangeRateStored(),
flags,
200_000,
200_000
);
}
}
return (new uint256[](parts), 0);
}
function calculateUniswapChai(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == dai && destToken.isETH() ||
fromToken.isETH() && destToken == dai)
{
return _calculateUniswapWrapped(
fromToken,
chai,
destToken,
amount,
parts,
chai.chaiPrice(),
flags,
180_000,
160_000
);
}
return (new uint256[](parts), 0);
}
function calculateUniswapAave(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
IERC20 midPreToken;
if (!fromToken.isETH() && destToken.isETH()) {
midPreToken = fromToken;
}
else if (!destToken.isETH() && fromToken.isETH()) {
midPreToken = destToken;
}
if (!midPreToken.isETH()) {
IAaveToken midToken = aaveRegistry.aTokenByToken(midPreToken);
if (midToken != IAaveToken(0)) {
return _calculateUniswapWrapped(
fromToken,
midToken,
destToken,
amount,
parts,
1e18,
flags,
310_000,
670_000
);
}
}
return (new uint256[](parts), 0);
}
function calculateKyber1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xff4b796265722046707200000000000000000000000000000000000000000000 // 0x63825c174ab367968EC60f061753D3bbD36A0D8F
);
}
function calculateKyber2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xffabcd0000000000000000000000000000000000000000000000000000000000 // 0x7a3370075a54B187d7bD5DceBf0ff2B5552d4F7D
);
}
function calculateKyber3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
0xff4f6e65426974205175616e7400000000000000000000000000000000000000 // 0x4f32BbE8dFc9efD54345Fc936f9fEF1048746fCF
);
}
function calculateKyber4(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
bytes32 reserveId = _kyberReserveIdByTokens(fromToken, destToken);
if (reserveId == 0) {
return (new uint256[](parts), 0);
}
return _calculateKyber(
fromToken,
destToken,
amount,
parts,
flags,
reserveId
);
}
function _kyberGetRate(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags,
bytes memory hint
) private view returns(uint256) {
(, bytes memory data) = address(kyberNetworkProxy).staticcall(
abi.encodeWithSelector(
kyberNetworkProxy.getExpectedRateAfterFee.selector,
fromToken,
destToken,
amount,
flags.check(1 << 255) ? 10 : 0,
hint
)
);
return (data.length == 32) ? abi.decode(data, (uint256)) : 0;
}
function _calculateKyber(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
bytes32 reserveId
) internal view returns(uint256[] memory rets, uint256 gas) {
bytes memory fromHint;
bytes memory destHint;
{
bytes32[] memory reserveIds = new bytes32[](1);
reserveIds[0] = reserveId;
(bool success, bytes memory data) = address(kyberHintHandler).staticcall(
abi.encodeWithSelector(
kyberHintHandler.buildTokenToEthHint.selector,
fromToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
)
);
fromHint = success ? abi.decode(data, (bytes)) : bytes("");
(success, data) = address(kyberHintHandler).staticcall(
abi.encodeWithSelector(
kyberHintHandler.buildEthToTokenHint.selector,
destToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
)
);
destHint = success ? abi.decode(data, (bytes)) : bytes("");
}
uint256 fromTokenDecimals = 10 ** IERC20(fromToken).universalDecimals();
uint256 destTokenDecimals = 10 ** IERC20(destToken).universalDecimals();
rets = new uint256[](parts);
for (uint i = 0; i < parts; i++) {
if (i > 0 && rets[i - 1] == 0) {
break;
}
rets[i] = amount.mul(i + 1).div(parts);
if (!fromToken.isETH()) {
if (fromHint.length == 0) {
rets[i] = 0;
break;
}
uint256 rate = _kyberGetRate(
fromToken,
ETH_ADDRESS,
rets[i],
flags,
fromHint
);
rets[i] = rate.mul(rets[i]).div(fromTokenDecimals);
}
if (!destToken.isETH() && rets[i] > 0) {
if (destHint.length == 0) {
rets[i] = 0;
break;
}
uint256 rate = _kyberGetRate(
ETH_ADDRESS,
destToken,
rets[i],
flags.check(1 << 255) ? 10 : 0,
destHint
);
rets[i] = rate.mul(rets[i]).mul(destTokenDecimals).div(1e36);
}
}
return (rets, 100_000);
}
function calculateBancor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork"));
address[] memory path = bancorFinder.buildBancorPath(
fromToken.isETH() ? bancorEtherToken : fromToken,
destToken.isETH() ? bancorEtherToken : destToken
);
rets = _linearInterpolation(amount, parts);
for (uint i = 0; i < parts; i++) {
(bool success, bytes memory data) = address(bancorNetwork).staticcall.gas(500000)(
abi.encodeWithSelector(
bancorNetwork.getReturnByPath.selector,
path,
rets[i]
)
);
if (!success || data.length == 0) {
for (; i < parts; i++) {
rets[i] = 0;
}
break;
} else {
(uint256 ret,) = abi.decode(data, (uint256,uint256));
rets[i] = ret;
}
}
return (rets, path.length.mul(150_000));
}
function calculateOasis(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = _linearInterpolation(amount, parts);
for (uint i = 0; i < parts; i++) {
(bool success, bytes memory data) = address(oasisExchange).staticcall.gas(500000)(
abi.encodeWithSelector(
oasisExchange.getBuyAmount.selector,
destToken.isETH() ? weth : destToken,
fromToken.isETH() ? weth : fromToken,
rets[i]
)
);
if (!success || data.length == 0) {
for (; i < parts; i++) {
rets[i] = 0;
}
break;
} else {
rets[i] = abi.decode(data, (uint256));
}
}
return (rets, 500_000);
}
function calculateMooniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
IMooniswap mooniswap = mooniswapRegistry.target();
(bool success, bytes memory data) = address(mooniswap).staticcall.gas(1000000)(
abi.encodeWithSelector(
mooniswap.getReturn.selector,
fromToken,
destToken,
amount
)
);
if (!success || data.length == 0) {
return (new uint256[](parts), 0);
}
uint256 maxRet = abi.decode(data, (uint256));
return (_linearInterpolation(maxRet, parts), 1_000_000);
}
function calculateUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
return _calculateUniswapV2(
fromToken,
destToken,
_linearInterpolation(amount, parts),
flags
);
}
function calculateUniswapV2ETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken.isETH() || fromToken == weth || destToken.isETH() || destToken == weth) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
weth,
destToken,
amount,
parts,
flags
);
}
function calculateUniswapV2DAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == dai || destToken == dai) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
dai,
destToken,
amount,
parts,
flags
);
}
function calculateUniswapV2USDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
if (fromToken == usdc || destToken == usdc) {
return (new uint256[](parts), 0);
}
return _calculateUniswapV2OverMidToken(
fromToken,
usdc,
destToken,
amount,
parts,
flags
);
}
function _calculateUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256[] memory amounts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = new uint256[](amounts.length);
IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken;
IERC20 destTokenReal = destToken.isETH() ? weth : destToken;
IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, destTokenReal);
if (exchange != IUniswapV2Exchange(0)) {
uint256 fromTokenBalance = fromTokenReal.universalBalanceOf(address(exchange));
uint256 destTokenBalance = destTokenReal.universalBalanceOf(address(exchange));
for (uint i = 0; i < amounts.length; i++) {
rets[i] = _calculateUniswapFormula(fromTokenBalance, destTokenBalance, amounts[i]);
}
return (rets, 50_000);
}
}
function _calculateUniswapV2OverMidToken(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
) internal view returns(uint256[] memory rets, uint256 gas) {
rets = _linearInterpolation(amount, parts);
uint256 gas1;
uint256 gas2;
(rets, gas1) = _calculateUniswapV2(fromToken, midToken, rets, flags);
(rets, gas2) = _calculateUniswapV2(midToken, destToken, rets, flags);
return (rets, gas1 + gas2);
}
function _calculateNoReturn(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 parts,
uint256 /*flags*/
) internal view returns(uint256[] memory rets, uint256 gas) {
this;
return (new uint256[](parts), 0);
}
}
contract OneSplitBaseWrap is IOneSplit, OneSplitRoot {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags // See constants in IOneSplit.sol
) internal {
if (fromToken == destToken) {
return;
}
_swapFloor(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _swapFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 /*flags*/ // See constants in IOneSplit.sol
) internal;
}
contract OneSplit is IOneSplit, OneSplitRoot {
IOneSplitView public oneSplitView;
constructor(IOneSplitView _oneSplitView) public {
oneSplitView = _oneSplitView;
}
function() external payable {
// solium-disable-next-line security/no-tx-origin
require(msg.sender != tx.origin);
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags // See constants in IOneSplit.sol
) public payable returns(uint256 returnAmount) {
if (fromToken == destToken) {
return amount;
}
function(IERC20,IERC20,uint256,uint256)[DEXES_COUNT] memory reserves = [
_swapOnUniswap,
_swapOnNowhere,
_swapOnBancor,
_swapOnOasis,
_swapOnCurveCompound,
_swapOnCurveUSDT,
_swapOnCurveY,
_swapOnCurveBinance,
_swapOnCurveSynthetix,
_swapOnUniswapCompound,
_swapOnUniswapChai,
_swapOnUniswapAave,
_swapOnMooniswap,
_swapOnUniswapV2,
_swapOnUniswapV2ETH,
_swapOnUniswapV2DAI,
_swapOnUniswapV2USDC,
_swapOnCurvePAX,
_swapOnCurveRenBTC,
_swapOnCurveTBTC,
_swapOnDforceSwap,
_swapOnShell,
_swapOnMStableMUSD,
_swapOnCurveSBTC,
_swapOnBalancer1,
_swapOnBalancer2,
_swapOnBalancer3,
_swapOnKyber1,
_swapOnKyber2,
_swapOnKyber3,
_swapOnKyber4
];
require(distribution.length <= reserves.length, "OneSplit: Distribution array should not exceed reserves array size");
uint256 parts = 0;
uint256 lastNonZeroIndex = 0;
for (uint i = 0; i < distribution.length; i++) {
if (distribution[i] > 0) {
parts = parts.add(distribution[i]);
lastNonZeroIndex = i;
}
}
if (parts == 0) {
if (fromToken.isETH()) {
msg.sender.transfer(msg.value);
return msg.value;
}
return amount;
}
fromToken.universalTransferFrom(msg.sender, address(this), amount);
uint256 remainingAmount = fromToken.universalBalanceOf(address(this));
for (uint i = 0; i < distribution.length; i++) {
if (distribution[i] == 0) {
continue;
}
uint256 swapAmount = amount.mul(distribution[i]).div(parts);
if (i == lastNonZeroIndex) {
swapAmount = remainingAmount;
}
remainingAmount -= swapAmount;
reserves[i](fromToken, destToken, swapAmount, flags);
}
returnAmount = destToken.universalBalanceOf(address(this));
require(returnAmount >= minReturn, "OneSplit: Return amount was not enough");
destToken.universalTransfer(msg.sender, returnAmount);
fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this)));
}
// Swap helpers
function _swapOnCurveCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) + (fromToken == usdc ? 2 : 0);
int128 j = (destToken == dai ? 1 : 0) + (destToken == usdc ? 2 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveCompound), amount);
curveCompound.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveUSDT(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveUSDT), amount);
curveUSDT.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveY(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == tusd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == tusd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveY), amount);
curveY.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveBinance(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == busd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == busd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveBinance), amount);
curveBinance.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurveSynthetix(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == susd ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == susd ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveSynthetix), amount);
curveSynthetix.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnCurvePAX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == dai ? 1 : 0) +
(fromToken == usdc ? 2 : 0) +
(fromToken == usdt ? 3 : 0) +
(fromToken == pax ? 4 : 0);
int128 j = (destToken == dai ? 1 : 0) +
(destToken == usdc ? 2 : 0) +
(destToken == usdt ? 3 : 0) +
(destToken == pax ? 4 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curvePAX), amount);
curvePAX.exchange_underlying(i - 1, j - 1, amount, 0);
}
function _swapOnShell(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(shell), amount);
shell.swapByOrigin(
address(fromToken),
address(destToken),
amount,
0,
now + 50
);
}
function _swapOnMStableMUSD(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(musd), amount);
musd.swap(
fromToken,
destToken,
amount,
address(this)
);
}
function _swapOnCurveRenBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == renbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0);
int128 j = (destToken == renbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveRenBTC), amount);
curveRenBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnCurveTBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == tbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0) +
(fromToken == hbtc ? 3 : 0);
int128 j = (destToken == tbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0) +
(destToken == hbtc ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveTBTC), amount);
curveTBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnCurveSBTC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
int128 i = (fromToken == renbtc ? 1 : 0) +
(fromToken == wbtc ? 2 : 0) +
(fromToken == sbtc ? 3 : 0);
int128 j = (destToken == renbtc ? 1 : 0) +
(destToken == wbtc ? 2 : 0) +
(destToken == sbtc ? 3 : 0);
if (i == 0 || j == 0) {
return;
}
fromToken.universalApprove(address(curveSBTC), amount);
curveSBTC.exchange(i - 1, j - 1, amount, 0);
}
function _swapOnDforceSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
fromToken.universalApprove(address(dforceSwap), amount);
dforceSwap.swap(fromToken, destToken, amount);
}
function _swapOnUniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
uint256 returnAmount = amount;
if (!fromToken.isETH()) {
IUniswapExchange fromExchange = uniswapFactory.getExchange(fromToken);
if (fromExchange != IUniswapExchange(0)) {
fromToken.universalApprove(address(fromExchange), returnAmount);
returnAmount = fromExchange.tokenToEthSwapInput(returnAmount, 1, now);
}
}
if (!destToken.isETH()) {
IUniswapExchange toExchange = uniswapFactory.getExchange(destToken);
if (toExchange != IUniswapExchange(0)) {
returnAmount = toExchange.ethToTokenSwapInput.value(returnAmount)(1, now);
}
}
}
function _swapOnUniswapCompound(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (!fromToken.isETH()) {
ICompoundToken fromCompound = compoundRegistry.cTokenByToken(fromToken);
fromToken.universalApprove(address(fromCompound), amount);
fromCompound.mint(amount);
_swapOnUniswap(IERC20(fromCompound), destToken, IERC20(fromCompound).universalBalanceOf(address(this)), flags);
return;
}
if (!destToken.isETH()) {
ICompoundToken toCompound = compoundRegistry.cTokenByToken(destToken);
_swapOnUniswap(fromToken, IERC20(toCompound), amount, flags);
toCompound.redeem(IERC20(toCompound).universalBalanceOf(address(this)));
destToken.universalBalanceOf(address(this));
return;
}
}
function _swapOnUniswapChai(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (fromToken == dai) {
fromToken.universalApprove(address(chai), amount);
chai.join(address(this), amount);
_swapOnUniswap(IERC20(chai), destToken, IERC20(chai).universalBalanceOf(address(this)), flags);
return;
}
if (destToken == dai) {
_swapOnUniswap(fromToken, IERC20(chai), amount, flags);
chai.exit(address(this), chai.balanceOf(address(this)));
return;
}
}
function _swapOnUniswapAave(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
if (!fromToken.isETH()) {
IAaveToken fromAave = aaveRegistry.aTokenByToken(fromToken);
fromToken.universalApprove(aave.core(), amount);
aave.deposit(fromToken, amount, 1101);
_swapOnUniswap(IERC20(fromAave), destToken, IERC20(fromAave).universalBalanceOf(address(this)), flags);
return;
}
if (!destToken.isETH()) {
IAaveToken toAave = aaveRegistry.aTokenByToken(destToken);
_swapOnUniswap(fromToken, IERC20(toAave), amount, flags);
toAave.redeem(toAave.balanceOf(address(this)));
return;
}
}
function _swapOnMooniswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
IMooniswap mooniswap = mooniswapRegistry.target();
fromToken.universalApprove(address(mooniswap), amount);
mooniswap.swap.value(fromToken.isETH() ? amount : 0)(
fromToken,
destToken,
amount,
0
);
}
function _swapOnNowhere(
IERC20 /*fromToken*/,
IERC20 /*destToken*/,
uint256 /*amount*/,
uint256 /*flags*/
) internal {
revert("This source was deprecated");
}
function _swapOnKyber1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xff4b796265722046707200000000000000000000000000000000000000000000
);
}
function _swapOnKyber2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xffabcd0000000000000000000000000000000000000000000000000000000000
);
}
function _swapOnKyber3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
0xff4f6e65426974205175616e7400000000000000000000000000000000000000
);
}
function _swapOnKyber4(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnKyber(
fromToken,
destToken,
amount,
flags,
_kyberReserveIdByTokens(fromToken, destToken)
);
}
function _swapOnKyber(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags,
bytes32 reserveId
) internal {
uint256 returnAmount = amount;
uint256 bps = flags.check(1 << 255) ? 10 : 0;
bytes32[] memory reserveIds = new bytes32[](1);
reserveIds[0] = reserveId;
if (!fromToken.isETH()) {
bytes memory fromHint = kyberHintHandler.buildTokenToEthHint(
fromToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
);
fromToken.universalApprove(address(kyberNetworkProxy), amount);
returnAmount = kyberNetworkProxy.tradeWithHintAndFee(
fromToken,
returnAmount,
ETH_ADDRESS,
address(this),
uint256(-1),
0,
0x4D37f28D2db99e8d35A6C725a5f1749A085850a3,
bps,
fromHint
);
}
if (!destToken.isETH()) {
bytes memory destHint = kyberHintHandler.buildEthToTokenHint(
destToken,
IKyberHintHandler.TradeType.MaskIn,
reserveIds,
new uint256[](0)
);
returnAmount = kyberNetworkProxy.tradeWithHintAndFee.value(returnAmount)(
ETH_ADDRESS,
returnAmount,
destToken,
address(this),
uint256(-1),
0,
0x4D37f28D2db99e8d35A6C725a5f1749A085850a3,
bps,
destHint
);
}
}
function _swapOnBancor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
IBancorNetwork bancorNetwork = IBancorNetwork(bancorContractRegistry.addressOf("BancorNetwork"));
address[] memory path = bancorNetworkPathFinder.generatePath(
fromToken.isETH() ? bancorEtherToken : fromToken,
destToken.isETH() ? bancorEtherToken : destToken
);
fromToken.universalApprove(address(bancorNetwork), amount);
bancorNetwork.convert.value(fromToken.isETH() ? amount : 0)(path, amount, 1);
}
function _swapOnOasis(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal {
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
IERC20 approveToken = fromToken.isETH() ? weth : fromToken;
approveToken.universalApprove(address(oasisExchange), amount);
oasisExchange.sellAllAmount(
fromToken.isETH() ? weth : fromToken,
amount,
destToken.isETH() ? weth : destToken,
1
);
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnUniswapV2Internal(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/
) internal returns(uint256 returnAmount) {
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken;
IERC20 toTokenReal = destToken.isETH() ? weth : destToken;
IUniswapV2Exchange exchange = uniswapV2.getPair(fromTokenReal, toTokenReal);
returnAmount = exchange.getReturn(fromTokenReal, toTokenReal, amount);
fromTokenReal.universalTransfer(address(exchange), amount);
if (uint256(address(fromTokenReal)) < uint256(address(toTokenReal))) {
exchange.swap(0, returnAmount, address(this), "");
} else {
exchange.swap(returnAmount, 0, address(this), "");
}
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnUniswapV2OverMid(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2Internal(
midToken,
destToken,
_swapOnUniswapV2Internal(
fromToken,
midToken,
amount,
flags
),
flags
);
}
function _swapOnUniswapV2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2Internal(
fromToken,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2ETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
weth,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2DAI(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
dai,
destToken,
amount,
flags
);
}
function _swapOnUniswapV2USDC(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnUniswapV2OverMid(
fromToken,
usdc,
destToken,
amount,
flags
);
}
function _swapOnBalancerX(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 /*flags*/,
uint256 poolIndex
) internal {
address[] memory pools = balancerRegistry.getBestPoolsWithLimit(
address(fromToken.isETH() ? weth : fromToken),
address(destToken.isETH() ? weth : destToken),
poolIndex + 1
);
if (fromToken.isETH()) {
weth.deposit.value(amount)();
}
(fromToken.isETH() ? weth : fromToken).universalApprove(pools[poolIndex], amount);
IBalancerPool(pools[poolIndex]).swapExactAmountIn(
fromToken.isETH() ? weth : fromToken,
amount,
destToken.isETH() ? weth : destToken,
0,
uint256(-1)
);
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOnBalancer1(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 0);
}
function _swapOnBalancer2(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 1);
}
function _swapOnBalancer3(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 flags
) internal {
_swapOnBalancerX(fromToken, destToken, amount, flags, 2);
}
}
// File: contracts/OneSplitCompound.sol
pragma solidity ^0.5.0;
contract OneSplitCompoundView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _compoundGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _compoundGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) {
IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken)));
if (underlying != IERC20(0)) {
uint256 compoundRate = ICompoundToken(address(fromToken)).exchangeRateStored();
(returnAmount, estimateGasAmount, distribution) = _compoundGetExpectedReturn(
underlying,
destToken,
amount.mul(compoundRate).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken)));
if (underlying != IERC20(0)) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 compoundRate = ICompoundToken(address(destToken)).exchangeRateStored();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(compoundRate).div(1e18)
);
return (returnAmount.mul(1e18).div(compoundRate), estimateGasAmount + 430_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitCompound is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_compoundSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _compoundSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_COMPOUND)) {
IERC20 underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(fromToken)));
if (underlying != IERC20(0)) {
ICompoundToken(address(fromToken)).redeem(amount);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
return _compoundSwap(
underlying,
destToken,
underlyingAmount,
distribution,
flags
);
}
underlying = compoundRegistry.tokenByCToken(ICompoundToken(address(destToken)));
if (underlying != IERC20(0)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
if (underlying.isETH()) {
cETH.mint.value(underlyingAmount)();
} else {
underlying.universalApprove(address(destToken), underlyingAmount);
ICompoundToken(address(destToken)).mint(underlyingAmount);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IFulcrum.sol
pragma solidity ^0.5.0;
contract IFulcrumToken is IERC20 {
function tokenPrice() external view returns (uint256);
function loanTokenAddress() external view returns (address);
function mintWithEther(address receiver) external payable returns (uint256 mintAmount);
function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);
function burnToEther(address receiver, uint256 burnAmount)
external
returns (uint256 loanAmountPaid);
function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);
}
// File: contracts/OneSplitFulcrum.sol
pragma solidity ^0.5.0;
contract OneSplitFulcrumBase {
using UniversalERC20 for IERC20;
function _isFulcrumToken(IERC20 token) internal view returns(IERC20) {
if (token.isETH()) {
return IERC20(-1);
}
(bool success, bytes memory data) = address(token).staticcall.gas(5000)(abi.encodeWithSignature(
"name()"
));
if (!success) {
return IERC20(-1);
}
bool foundBZX = false;
for (uint i = 0; i + 6 < data.length; i++) {
if (data[i + 0] == "F" &&
data[i + 1] == "u" &&
data[i + 2] == "l" &&
data[i + 3] == "c" &&
data[i + 4] == "r" &&
data[i + 5] == "u" &&
data[i + 6] == "m")
{
foundBZX = true;
break;
}
}
if (!foundBZX) {
return IERC20(-1);
}
(success, data) = address(token).staticcall.gas(5000)(abi.encodeWithSelector(
IFulcrumToken(address(token)).loanTokenAddress.selector
));
if (!success) {
return IERC20(-1);
}
return abi.decode(data, (IERC20));
}
}
contract OneSplitFulcrumView is OneSplitViewWrapBase, OneSplitFulcrumBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _fulcrumGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _fulcrumGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) {
IERC20 underlying = _isFulcrumToken(fromToken);
if (underlying != IERC20(-1)) {
uint256 fulcrumRate = IFulcrumToken(address(fromToken)).tokenPrice();
(returnAmount, estimateGasAmount, distribution) = _fulcrumGetExpectedReturn(
underlying,
destToken,
amount.mul(fulcrumRate).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 381_000, distribution);
}
underlying = _isFulcrumToken(destToken);
if (underlying != IERC20(-1)) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 fulcrumRate = IFulcrumToken(address(destToken)).tokenPrice();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(fulcrumRate).div(1e18)
);
return (returnAmount.mul(1e18).div(fulcrumRate), estimateGasAmount + 354_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitFulcrum is OneSplitBaseWrap, OneSplitFulcrumBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_fulcrumSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _fulcrumSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_FULCRUM)) {
IERC20 underlying = _isFulcrumToken(fromToken);
if (underlying != IERC20(-1)) {
if (underlying.isETH()) {
IFulcrumToken(address(fromToken)).burnToEther(address(this), amount);
} else {
IFulcrumToken(address(fromToken)).burn(address(this), amount);
}
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
return super._swap(
underlying,
destToken,
underlyingAmount,
distribution,
flags
);
}
underlying = _isFulcrumToken(destToken);
if (underlying != IERC20(-1)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
if (underlying.isETH()) {
IFulcrumToken(address(destToken)).mintWithEther.value(underlyingAmount)(address(this));
} else {
underlying.universalApprove(address(destToken), underlyingAmount);
IFulcrumToken(address(destToken)).mint(address(this), underlyingAmount);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitChai.sol
pragma solidity ^0.5.0;
contract OneSplitChaiView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) {
if (fromToken == IERC20(chai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
dai,
destToken,
chai.chaiToDai(amount),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 197_000, distribution);
}
if (destToken == IERC20(chai)) {
uint256 price = chai.chaiPrice();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
dai,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice.mul(1e18).div(price)
);
return (returnAmount.mul(price).div(1e18), estimateGasAmount + 168_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitChai is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_CHAI)) {
if (fromToken == IERC20(chai)) {
chai.exit(address(this), amount);
return super._swap(
dai,
destToken,
dai.balanceOf(address(this)),
distribution,
flags
);
}
if (destToken == IERC20(chai)) {
super._swap(
fromToken,
dai,
amount,
distribution,
flags
);
uint256 daiBalance = dai.balanceOf(address(this));
dai.universalApprove(address(chai), daiBalance);
chai.join(address(this), daiBalance);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IBdai.sol
pragma solidity ^0.5.0;
contract IBdai is IERC20 {
function join(uint256) external;
function exit(uint256) external;
}
// File: contracts/OneSplitBdai.sol
pragma solidity ^0.5.0;
contract OneSplitBdaiBase {
IBdai internal constant bdai = IBdai(0x6a4FFAafa8DD400676Df8076AD6c724867b0e2e8);
IERC20 internal constant btu = IERC20(0xb683D83a532e2Cb7DFa5275eED3698436371cc9f);
}
contract OneSplitBdaiView is OneSplitViewWrapBase, OneSplitBdaiBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) {
if (fromToken == IERC20(bdai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
dai,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 227_000, distribution);
}
if (destToken == IERC20(bdai)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
dai,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitBdai is OneSplitBaseWrap, OneSplitBdaiBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_BDAI)) {
if (fromToken == IERC20(bdai)) {
bdai.exit(amount);
uint256 btuBalance = btu.balanceOf(address(this));
if (btuBalance > 0) {
(,uint256[] memory btuDistribution) = getExpectedReturn(
btu,
destToken,
btuBalance,
1,
flags
);
_swap(
btu,
destToken,
btuBalance,
btuDistribution,
flags
);
}
return super._swap(
dai,
destToken,
amount,
distribution,
flags
);
}
if (destToken == IERC20(bdai)) {
super._swap(fromToken, dai, amount, distribution, flags);
uint256 daiBalance = dai.balanceOf(address(this));
dai.universalApprove(address(bdai), daiBalance);
bdai.join(daiBalance);
return;
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/interface/IIearn.sol
pragma solidity ^0.5.0;
contract IIearn is IERC20 {
function token() external view returns(IERC20);
function calcPoolValueInToken() external view returns(uint256);
function deposit(uint256 _amount) external;
function withdraw(uint256 _shares) external;
}
// File: contracts/OneSplitIearn.sol
pragma solidity ^0.5.0;
contract OneSplitIearnBase {
function _yTokens() internal pure returns(IIearn[13] memory) {
return [
IIearn(0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01),
IIearn(0x04Aa51bbcB46541455cCF1B8bef2ebc5d3787EC9),
IIearn(0x73a052500105205d34Daf004eAb301916DA8190f),
IIearn(0x83f798e925BcD4017Eb265844FDDAbb448f1707D),
IIearn(0xd6aD7a6750A7593E092a9B218d66C0A814a3436e),
IIearn(0xF61718057901F84C4eEC4339EF8f0D86D2B45600),
IIearn(0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE),
IIearn(0xC2cB1040220768554cf699b0d863A3cd4324ce32),
IIearn(0xE6354ed5bC4b393a5Aad09f21c46E101e692d447),
IIearn(0x26EA744E5B887E5205727f55dFBE8685e3b21951),
IIearn(0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc),
IIearn(0x9777d7E2b60bB01759D0E2f8be2095df444cb07E),
IIearn(0x1bE5d71F2dA660BFdee8012dDc58D024448A0A59)
];
}
}
contract OneSplitIearnView is OneSplitViewWrapBase, OneSplitIearnBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _iearnGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _iearnGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IEARN)) {
IIearn[13] memory yTokens = _yTokens();
for (uint i = 0; i < yTokens.length; i++) {
if (fromToken == IERC20(yTokens[i])) {
(returnAmount, estimateGasAmount, distribution) = _iearnGetExpectedReturn(
yTokens[i].token(),
destToken,
amount
.mul(yTokens[i].calcPoolValueInToken())
.div(yTokens[i].totalSupply()),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 260_000, distribution);
}
}
for (uint i = 0; i < yTokens.length; i++) {
if (destToken == IERC20(yTokens[i])) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
IERC20 token = yTokens[i].token();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
token,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice
.mul(yTokens[i].calcPoolValueInToken())
.div(yTokens[i].totalSupply())
);
return(
returnAmount
.mul(yTokens[i].totalSupply())
.div(yTokens[i].calcPoolValueInToken()),
estimateGasAmount + 743_000,
distribution
);
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitIearn is OneSplitBaseWrap, OneSplitIearnBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_iearnSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _iearnSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_IEARN)) {
IIearn[13] memory yTokens = _yTokens();
for (uint i = 0; i < yTokens.length; i++) {
if (fromToken == IERC20(yTokens[i])) {
IERC20 underlying = yTokens[i].token();
yTokens[i].withdraw(amount);
_iearnSwap(underlying, destToken, underlying.balanceOf(address(this)), distribution, flags);
return;
}
}
for (uint i = 0; i < yTokens.length; i++) {
if (destToken == IERC20(yTokens[i])) {
IERC20 underlying = yTokens[i].token();
super._swap(fromToken, underlying, amount, distribution, flags);
uint256 underlyingBalance = underlying.balanceOf(address(this));
underlying.universalApprove(address(yTokens[i]), underlyingBalance);
yTokens[i].deposit(underlyingBalance);
return;
}
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/interface/IIdle.sol
pragma solidity ^0.5.0;
contract IIdle is IERC20 {
function token()
external view returns (IERC20);
function tokenPrice()
external view returns (uint256);
function mintIdleToken(uint256 _amount, uint256[] calldata _clientProtocolAmounts)
external returns (uint256 mintedTokens);
function redeemIdleToken(uint256 _amount, bool _skipRebalance, uint256[] calldata _clientProtocolAmounts)
external returns (uint256 redeemedTokens);
}
// File: contracts/OneSplitIdle.sol
pragma solidity ^0.5.0;
contract OneSplitIdleBase {
function _idleTokens() internal pure returns(IIdle[8] memory) {
// https://developers.idle.finance/contracts-and-codebase
return [
// V3
IIdle(0x78751B12Da02728F467A44eAc40F5cbc16Bd7934),
IIdle(0x12B98C621E8754Ae70d0fDbBC73D6208bC3e3cA6),
IIdle(0x63D27B3DA94A9E871222CB0A32232674B02D2f2D),
IIdle(0x1846bdfDB6A0f5c473dEc610144513bd071999fB),
IIdle(0xcDdB1Bceb7a1979C6caa0229820707429dd3Ec6C),
IIdle(0x42740698959761BAF1B06baa51EfBD88CB1D862B),
// V2
IIdle(0x10eC0D497824e342bCB0EDcE00959142aAa766dD),
IIdle(0xeB66ACc3d011056B00ea521F8203580C2E5d3991)
];
}
}
contract OneSplitIdleView is OneSplitViewWrapBase, OneSplitIdleBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _idleGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _idleGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) {
IIdle[8] memory tokens = _idleTokens();
for (uint i = 0; i < tokens.length; i++) {
if (fromToken == IERC20(tokens[i])) {
(returnAmount, estimateGasAmount, distribution) = _idleGetExpectedReturn(
tokens[i].token(),
destToken,
amount.mul(tokens[i].tokenPrice()).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 2_400_000, distribution);
}
}
for (uint i = 0; i < tokens.length; i++) {
if (destToken == IERC20(tokens[i])) {
uint256 _destTokenEthPriceTimesGasPrice = destTokenEthPriceTimesGasPrice;
uint256 _price = tokens[i].tokenPrice();
IERC20 token = tokens[i].token();
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
token,
amount,
parts,
flags,
_destTokenEthPriceTimesGasPrice.mul(_price).div(1e18)
);
return (returnAmount.mul(1e18).div(_price), estimateGasAmount + 1_300_000, distribution);
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitIdle is OneSplitBaseWrap, OneSplitIdleBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_idleSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _idleSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (!flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == !flags.check(FLAG_DISABLE_IDLE)) {
IIdle[8] memory tokens = _idleTokens();
for (uint i = 0; i < tokens.length; i++) {
if (fromToken == IERC20(tokens[i])) {
IERC20 underlying = tokens[i].token();
uint256 minted = tokens[i].redeemIdleToken(amount, true, new uint256[](0));
_idleSwap(underlying, destToken, minted, distribution, flags);
return;
}
}
for (uint i = 0; i < tokens.length; i++) {
if (destToken == IERC20(tokens[i])) {
IERC20 underlying = tokens[i].token();
super._swap(fromToken, underlying, amount, distribution, flags);
uint256 underlyingBalance = underlying.balanceOf(address(this));
underlying.universalApprove(address(tokens[i]), underlyingBalance);
tokens[i].mintIdleToken(underlyingBalance, new uint256[](0));
return;
}
}
}
return super._swap(fromToken, destToken, amount, distribution, flags);
}
}
// File: contracts/OneSplitAave.sol
pragma solidity ^0.5.0;
contract OneSplitAaveView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _aaveGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _aaveGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) {
IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken)));
if (underlying != IERC20(0)) {
(returnAmount, estimateGasAmount, distribution) = _aaveGetExpectedReturn(
underlying,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 670_000, distribution);
}
underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken)));
if (underlying != IERC20(0)) {
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 310_000, distribution);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitAave is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_aaveSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _aaveSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_AAVE)) {
IERC20 underlying = aaveRegistry.tokenByAToken(IAaveToken(address(fromToken)));
if (underlying != IERC20(0)) {
IAaveToken(address(fromToken)).redeem(amount);
return _aaveSwap(
underlying,
destToken,
amount,
distribution,
flags
);
}
underlying = aaveRegistry.tokenByAToken(IAaveToken(address(destToken)));
if (underlying != IERC20(0)) {
super._swap(
fromToken,
underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = underlying.universalBalanceOf(address(this));
underlying.universalApprove(aave.core(), underlyingAmount);
aave.deposit.value(underlying.isETH() ? underlyingAmount : 0)(
underlying.isETH() ? ETH_ADDRESS : underlying,
underlyingAmount,
1101
);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitWeth.sol
pragma solidity ^0.5.0;
contract OneSplitWethView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _wethGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _wethGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) {
if (fromToken == weth || fromToken == bancorEtherToken) {
return super.getExpectedReturnWithGas(ETH_ADDRESS, destToken, amount, parts, flags, destTokenEthPriceTimesGasPrice);
}
if (destToken == weth || destToken == bancorEtherToken) {
return super.getExpectedReturnWithGas(fromToken, ETH_ADDRESS, amount, parts, flags, destTokenEthPriceTimesGasPrice);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitWeth is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_wethSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _wethSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_WETH)) {
if (fromToken == weth) {
weth.withdraw(weth.balanceOf(address(this)));
super._swap(
ETH_ADDRESS,
destToken,
amount,
distribution,
flags
);
return;
}
if (fromToken == bancorEtherToken) {
bancorEtherToken.withdraw(bancorEtherToken.balanceOf(address(this)));
super._swap(
ETH_ADDRESS,
destToken,
amount,
distribution,
flags
);
return;
}
if (destToken == weth) {
_wethSwap(
fromToken,
ETH_ADDRESS,
amount,
distribution,
flags
);
weth.deposit.value(address(this).balance)();
return;
}
if (destToken == bancorEtherToken) {
_wethSwap(
fromToken,
ETH_ADDRESS,
amount,
distribution,
flags
);
bancorEtherToken.deposit.value(address(this).balance)();
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplitMStable.sol
pragma solidity ^0.5.0;
contract OneSplitMStableView is OneSplitViewWrapBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) {
if (fromToken == IERC20(musd)) {
if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) {
(,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, destToken);
return (returnAmount, 300_000, new uint256[](DEXES_COUNT));
}
else {
(,, returnAmount) = musd_helper.getRedeemValidity(fromToken, amount, dai);
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
dai,
destToken,
returnAmount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 300_000, distribution);
}
}
if (destToken == IERC20(musd)) {
if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) {
(,, returnAmount) = musd.getSwapOutput(fromToken, destToken, amount);
return (returnAmount, 300_000, new uint256[](DEXES_COUNT));
}
else {
IERC20 _destToken = destToken;
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
dai,
amount,
parts,
flags,
_scaleDestTokenEthPriceTimesGasPrice(
_destToken,
dai,
destTokenEthPriceTimesGasPrice
)
);
(,, returnAmount) = musd_helper.getRedeemValidity(dai, returnAmount, destToken);
return (returnAmount, estimateGasAmount + 300_000, distribution);
}
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitMStable is OneSplitBaseWrap {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_MSTABLE_MUSD)) {
if (fromToken == IERC20(musd)) {
if (destToken == usdc || destToken == dai || destToken == usdt || destToken == tusd) {
(,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, destToken);
musd.redeem(
destToken,
result
);
}
else {
(,, uint256 result) = musd_helper.getRedeemValidity(fromToken, amount, dai);
musd.redeem(
dai,
result
);
super._swap(
dai,
destToken,
dai.balanceOf(address(this)),
distribution,
flags
);
}
return;
}
if (destToken == IERC20(musd)) {
if (fromToken == usdc || fromToken == dai || fromToken == usdt || fromToken == tusd) {
fromToken.universalApprove(address(musd), amount);
musd.swap(
fromToken,
destToken,
amount,
address(this)
);
}
else {
super._swap(
fromToken,
dai,
amount,
distribution,
flags
);
musd.swap(
dai,
destToken,
dai.balanceOf(address(this)),
address(this)
);
}
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/interface/IDMM.sol
pragma solidity ^0.5.0;
interface IDMMController {
function getUnderlyingTokenForDmm(IERC20 token) external view returns(IERC20);
}
contract IDMM is IERC20 {
function getCurrentExchangeRate() public view returns(uint256);
function mint(uint256 underlyingAmount) public returns(uint256);
function redeem(uint256 amount) public returns(uint256);
}
// File: contracts/OneSplitDMM.sol
pragma solidity ^0.5.0;
contract OneSplitDMMBase {
IDMMController internal constant _dmmController = IDMMController(0x4CB120Dd1D33C9A3De8Bc15620C7Cd43418d77E2);
function _getDMMUnderlyingToken(IERC20 token) internal view returns(IERC20) {
(bool success, bytes memory data) = address(_dmmController).staticcall(
abi.encodeWithSelector(
_dmmController.getUnderlyingTokenForDmm.selector,
token
)
);
if (!success || data.length == 0) {
return IERC20(-1);
}
return abi.decode(data, (IERC20));
}
function _getDMMExchangeRate(IDMM dmm) internal view returns(uint256) {
(bool success, bytes memory data) = address(dmm).staticcall(
abi.encodeWithSelector(
dmm.getCurrentExchangeRate.selector
)
);
if (!success || data.length == 0) {
return 0;
}
return abi.decode(data, (uint256));
}
}
contract OneSplitDMMView is OneSplitViewWrapBase, OneSplitDMMBase {
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return _dmmGetExpectedReturn(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _dmmGetExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
private
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) {
IERC20 underlying = _getDMMUnderlyingToken(fromToken);
if (underlying != IERC20(-1)) {
if (underlying == weth) {
underlying = ETH_ADDRESS;
}
IERC20 _fromToken = fromToken;
(returnAmount, estimateGasAmount, distribution) = _dmmGetExpectedReturn(
underlying,
destToken,
amount.mul(_getDMMExchangeRate(IDMM(address(_fromToken)))).div(1e18),
parts,
flags,
destTokenEthPriceTimesGasPrice
);
return (returnAmount, estimateGasAmount + 295_000, distribution);
}
underlying = _getDMMUnderlyingToken(destToken);
if (underlying != IERC20(-1)) {
if (underlying == weth) {
underlying = ETH_ADDRESS;
}
uint256 price = _getDMMExchangeRate(IDMM(address(destToken)));
(returnAmount, estimateGasAmount, distribution) = super.getExpectedReturnWithGas(
fromToken,
underlying,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice.mul(price).div(1e18)
);
return (
returnAmount.mul(1e18).div(price),
estimateGasAmount + 430_000,
distribution
);
}
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitDMM is OneSplitBaseWrap, OneSplitDMMBase {
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
_dmmSwap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
function _dmmSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) private {
if (fromToken == destToken) {
return;
}
if (flags.check(FLAG_DISABLE_ALL_WRAP_SOURCES) == flags.check(FLAG_DISABLE_DMM)) {
IERC20 underlying = _getDMMUnderlyingToken(fromToken);
if (underlying != IERC20(-1)) {
IDMM(address(fromToken)).redeem(amount);
uint256 balance = underlying.universalBalanceOf(address(this));
if (underlying == weth) {
weth.withdraw(balance);
}
_dmmSwap(
(underlying == weth) ? ETH_ADDRESS : underlying,
destToken,
balance,
distribution,
flags
);
}
underlying = _getDMMUnderlyingToken(destToken);
if (underlying != IERC20(-1)) {
super._swap(
fromToken,
(underlying == weth) ? ETH_ADDRESS : underlying,
amount,
distribution,
flags
);
uint256 underlyingAmount = ((underlying == weth) ? ETH_ADDRESS : underlying).universalBalanceOf(address(this));
if (underlying == weth) {
weth.deposit.value(underlyingAmount);
}
underlying.universalApprove(address(destToken), underlyingAmount);
IDMM(address(destToken)).mint(underlyingAmount);
return;
}
}
return super._swap(
fromToken,
destToken,
amount,
distribution,
flags
);
}
}
// File: contracts/OneSplit.sol
pragma solidity ^0.5.0;
contract OneSplitViewWrap is
OneSplitViewWrapBase,
OneSplitMStableView,
OneSplitChaiView,
OneSplitBdaiView,
OneSplitAaveView,
OneSplitFulcrumView,
OneSplitCompoundView,
OneSplitIearnView,
OneSplitIdleView,
OneSplitWethView,
OneSplitDMMView
{
IOneSplitView public oneSplitView;
constructor(IOneSplitView _oneSplit) public {
oneSplitView = _oneSplit;
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags, // See constants in IOneSplit.sol
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
if (fromToken == destToken) {
return (amount, 0, new uint256[](DEXES_COUNT));
}
return super.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function _getExpectedReturnRespectingGasFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
internal
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
}
contract OneSplitWrap is
OneSplitBaseWrap,
OneSplitMStable,
OneSplitChai,
OneSplitBdai,
OneSplitAave,
OneSplitFulcrum,
OneSplitCompound,
OneSplitIearn,
OneSplitIdle,
OneSplitWeth,
OneSplitDMM
{
IOneSplitView public oneSplitView;
IOneSplit public oneSplit;
constructor(IOneSplitView _oneSplitView, IOneSplit _oneSplit) public {
oneSplitView = _oneSplitView;
oneSplit = _oneSplit;
}
function() external payable {
// solium-disable-next-line security/no-tx-origin
require(msg.sender != tx.origin);
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
public
view
returns(
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, , distribution) = getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
0
);
}
function getExpectedReturnWithGas(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts,
uint256 flags,
uint256 destTokenEthPriceTimesGasPrice
)
public
view
returns(
uint256 returnAmount,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
return oneSplitView.getExpectedReturnWithGas(
fromToken,
destToken,
amount,
parts,
flags,
destTokenEthPriceTimesGasPrice
);
}
function getExpectedReturnWithGasMulti(
IERC20[] memory tokens,
uint256 amount,
uint256[] memory parts,
uint256[] memory flags,
uint256[] memory destTokenEthPriceTimesGasPrices
)
public
view
returns(
uint256[] memory returnAmounts,
uint256 estimateGasAmount,
uint256[] memory distribution
)
{
uint256[] memory dist;
returnAmounts = new uint256[](tokens.length - 1);
for (uint i = 1; i < tokens.length; i++) {
if (tokens[i - 1] == tokens[i]) {
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],
flags[i],
destTokenEthPriceTimesGasPrices[i]
);
estimateGasAmount = estimateGasAmount.add(amount);
if (distribution.length == 0) {
distribution = new uint256[](dist.length);
}
for (uint j = 0; j < distribution.length; j++) {
distribution[j] = distribution[j].add(dist[j] << (8 * (i - 1)));
}
}
}
function swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256 flags
) public payable returns(uint256 returnAmount) {
fromToken.universalTransferFrom(msg.sender, address(this), amount);
uint256 confirmed = fromToken.universalBalanceOf(address(this));
_swap(fromToken, destToken, confirmed, distribution, flags);
returnAmount = destToken.universalBalanceOf(address(this));
require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn");
destToken.universalTransfer(msg.sender, returnAmount);
fromToken.universalTransfer(msg.sender, fromToken.universalBalanceOf(address(this)));
}
function swapMulti(
IERC20[] memory tokens,
uint256 amount,
uint256 minReturn,
uint256[] memory distribution,
uint256[] memory flags
) public payable returns(uint256 returnAmount) {
tokens[0].universalTransferFrom(msg.sender, address(this), amount);
returnAmount = tokens[0].universalBalanceOf(address(this));
for (uint i = 1; i < tokens.length; i++) {
if (tokens[i - 1] == tokens[i]) {
continue;
}
uint256[] memory dist = new uint256[](distribution.length);
for (uint j = 0; j < distribution.length; j++) {
dist[j] = (distribution[j] >> (8 * (i - 1))) & 0xFF;
}
_swap(
tokens[i - 1],
tokens[i],
returnAmount,
dist,
flags[i]
);
returnAmount = tokens[i].universalBalanceOf(address(this));
tokens[i - 1].universalTransfer(msg.sender, tokens[i - 1].universalBalanceOf(address(this)));
}
require(returnAmount >= minReturn, "OneSplit: actual return amount is less than minReturn");
tokens[tokens.length - 1].universalTransfer(msg.sender, returnAmount);
}
function _swapFloor(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256[] memory distribution,
uint256 flags
) internal {
fromToken.universalApprove(address(oneSplit), amount);
oneSplit.swap.value(fromToken.isETH() ? amount : 0)(
fromToken,
destToken,
amount,
0,
distribution,
flags
);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IOneSplitView","name":"_oneSplitView","type":"address"},{"internalType":"contract IOneSplit","name":"_oneSplit","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"getExpectedReturn","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"destTokenEthPriceTimesGasPrice","type":"uint256"}],"name":"getExpectedReturnWithGas","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256[]","name":"parts","type":"uint256[]"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"uint256[]","name":"destTokenEthPriceTimesGasPrices","type":"uint256[]"}],"name":"getExpectedReturnWithGasMulti","outputs":[{"internalType":"uint256[]","name":"returnAmounts","type":"uint256[]"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplit","outputs":[{"internalType":"contract IOneSplit","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oneSplitView","outputs":[{"internalType":"contract IOneSplitView","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256","name":"flags","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"}],"name":"swapMulti","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5060405162004865380380620048658339818101604052604081101561003557600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b031991821617909155600180549390921692169190911790556147e8806200007d6000396000f3fe6080604052600436106100705760003560e01c80638373f2651161004e5780638373f26514610436578063c7851396146104ed578063e2a7515e146106b0578063fbe4ed951461077857610070565b8063085e2c5b1461007f57806343ee21f0146101295780637b33701a1461015a575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b0381358116916020810135909116906040810135906060810135906080013561078d565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b34801561013557600080fd5b5061013e6107b0565b604080516001600160a01b039092168252519081900360200190f35b34801561016657600080fd5b50610396600480360360a081101561017d57600080fd5b810190602081018135600160201b81111561019757600080fd5b8201836020820111156101a957600080fd5b803590602001918460208302840111600160201b831117156101ca57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561022157600080fd5b82018360208201111561023357600080fd5b803590602001918460208302840111600160201b8311171561025457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460208302840111600160201b831117156102d657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561032557600080fd5b82018360208201111561033757600080fd5b803590602001918460208302840111600160201b8311171561035857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107bf945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b838110156103e05781810151838201526020016103c8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561041f578181015183820152602001610407565b505050509050019550505050505060405180910390f35b34801561044257600080fd5b5061048b600480360360c081101561045957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a17565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156104d75781810151838201526020016104bf565b5050505090500194505050505060405180910390f35b61069e600480360360a081101561050357600080fd5b810190602081018135600160201b81111561051d57600080fd5b82018360208201111561052f57600080fd5b803590602001918460208302840111600160201b8311171561055057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156105ab57600080fd5b8201836020820111156105bd57600080fd5b803590602001918460208302840111600160201b831117156105de57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561062d57600080fd5b82018360208201111561063f57600080fd5b803590602001918460208302840111600160201b8311171561066057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610b6e945050505050565b60408051918252519081900360200190f35b61069e600480360360c08110156106c657600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561070557600080fd5b82018360208201111561071757600080fd5b803590602001918460208302840111600160201b8311171561073857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610db1915050565b34801561078457600080fd5b5061013e610ead565b600060606107a087878787876000610a17565b9199919850909650505050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156107f4578160200160208202803883390190505b50935060015b8951811015610a0a5789818151811061080f57fe5b60200260200101516001600160a01b03168a600183038151811061082f57fe5b60200260200101516001600160a01b0316141561088c578060011461086a5784600282038151811061085d57fe5b602002602001015161086c565b885b85600183038151811061087b57fe5b602002602001018181525050610a02565b60608a90506109268160018403815181106108a357fe5b60200260200101518284815181106108b757fe5b6020026020010151846001146108e3578860028603815181106108d657fe5b60200260200101516108e5565b8c5b8c86815181106108f157fe5b60200260200101518c878151811061090557fe5b60200260200101518c888151811061091957fe5b6020026020010151610a17565b88600186038151811061093557fe5b60209081029190910101929092529a509250610957858b63ffffffff610ebc16565b945083516000141561099257825160405190808252806020026020018201604052801561098e578160200160208202803883390190505b5093505b60005b84518110156109ff576109e0600184036008028583815181106109b457fe5b6020026020010151901b8683815181106109ca57fe5b6020026020010151610ebc90919063ffffffff16565b8582815181106109ec57fe5b6020908102919091010152600101610995565b50505b6001016107fa565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610a8a57600080fd5b505afa158015610a9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610ac757600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610af157600080fd5b908301906020820185811115610b0657600080fd5b82518660208202830111600160201b82111715610b2257600080fd5b82525081516020918201928201910280838360005b83811015610b4f578181015183820152602001610b37565b5050505090500160405250505092509250925096509650969350505050565b6000610ba433308789600081518110610b8357fe5b60200260200101516001600160a01b0316610f1f909392919063ffffffff16565b610bd43087600081518110610bb557fe5b60200260200101516001600160a01b031661103e90919063ffffffff16565b905060015b8651811015610d5257868181518110610bee57fe5b60200260200101516001600160a01b0316876001830381518110610c0e57fe5b60200260200101516001600160a01b03161415610c2a57610d4a565b60608451604051908082528060200260200182016040528015610c57578160200160208202803883390190505b50905060005b8551811015610ca55760018303600802868281518110610c7957fe5b6020026020010151901c60ff16828281518110610c9257fe5b6020908102919091010152600101610c5d565b50610cef886001840381518110610cb857fe5b6020026020010151898481518110610ccc57fe5b60200260200101518584888781518110610ce257fe5b60200260200101516110e8565b610cff30898481518110610bb557fe5b9250610d4733610d18308b6001870381518110610bb557fe5b8a6001860381518110610d2757fe5b60200260200101516001600160a01b03166110fc9092919063ffffffff16565b50505b600101610bd9565b5083811015610d925760405162461bcd60e51b81526004018080602001828103825260358152602001806146d46035913960400191505060405180910390fd5b610da733828860018a510381518110610d2757fe5b5095945050505050565b6000610dce6001600160a01b03881633308863ffffffff610f1f16565b6000610de96001600160a01b0389163063ffffffff61103e16565b9050610df888888387876110e8565b610e116001600160a01b0388163063ffffffff61103e16565b915084821015610e525760405162461bcd60e51b81526004018080602001828103825260358152602001806146d46035913960400191505060405180910390fd5b610e6c6001600160a01b038816338463ffffffff6110fc16565b50610ea133610e8a6001600160a01b038b163063ffffffff61103e16565b6001600160a01b038b16919063ffffffff6110fc16565b50509695505050505050565b6000546001600160a01b031681565b600082820183811015610f16576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b80610f2957611038565b610f328461117a565b1561101d576001600160a01b03831633148015610f4f5750803410155b610f8a5760405162461bcd60e51b815260040180806020018281038252602b815260200180614729602b913960400191505060405180910390fd5b6001600160a01b0382163014610fd2576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fd0573d6000803e3d6000fd5b505b8034111561101857336108fc610fee348463ffffffff6111b616565b6040518115909202916000818181858888f19350505050158015611016573d6000803e3d6000fd5b505b611038565b6110386001600160a01b03851684848463ffffffff6111f816565b50505050565b60006110498361117a565b1561105f57506001600160a01b03811631610f19565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110b557600080fd5b505afa1580156110c9573d6000803e3d6000fd5b505050506040513d60208110156110df57600080fd5b50519050610f19565b6110f58585858585611252565b5050505050565b60008161110b57506001611173565b6111148461117a565b15611155576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561114f573d6000803e3d6000fd5b50611173565b61116f6001600160a01b038516848463ffffffff6115a016565b5060015b9392505050565b60006001600160a01b03821615806111ae57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b6000610f1683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506115f7565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261103890859061168e565b836001600160a01b0316856001600160a01b03161415611271576110f5565b611287816508000000000063ffffffff61184616565b151561129d82634000000063ffffffff61184616565b151514156115935760006112b08661184c565b90506001600160a01b038082161461143857856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561130857600080fd5b505af115801561131c573d6000803e3d6000fd5b505050506040513d602081101561133257600080fd5b50600090506113506001600160a01b0383163063ffffffff61103e16565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156113ea5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156113d157600080fd5b505af11580156113e5573d6000803e3d6000fd5b505050505b6114366001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214611417578261142d565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b87838787611252565b505b6114418561184c565b90506001600160a01b03808216146115915761149f866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146114815782611497565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686611980565b60006114fa306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146114cf57836114e5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff61103e16565b90505b6115176001600160a01b038316878363ffffffff61198d16565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561155d57600080fd5b505af1158015611571573d6000803e3d6000fd5b505050506040513d602081101561158757600080fd5b506110f592505050565b505b6110f58585858585611980565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526115f290849061168e565b505050565b600081848411156116865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561164b578181015183820152602001611633565b50505050905090810190601f1680156116785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6116a0826001600160a01b0316611a81565b6116f1576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b6020831061172f5780518252601f199092019160209182019101611710565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611791576040519150601f19603f3d011682016040523d82523d6000602084013e611796565b606091505b5091509150816117ed576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156110385780806020019051602081101561180957600080fd5b50516110385760405162461bcd60e51b815260040180806020018281038252602a815260200180614754602a913960400191505060405180910390fd5b16151590565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b602083106118da5780518252601f1990920191602091820191016118bb565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461193a576040519150601f19603f3d011682016040523d82523d6000602084013e61193f565b606091505b509150915081158061195057508051155b1561196157600019925050506111b1565b80806020019051602081101561197657600080fd5b5051949350505050565b6110f58585858585611abd565b6119968361117a565b6115f257806119bf576119ba6001600160a01b03841683600063ffffffff611e0616565b6115f2565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611a1057600080fd5b505afa158015611a24573d6000803e3d6000fd5b505050506040513d6020811015611a3a57600080fd5b5051905081811015611038578015611a6757611a676001600160a01b03851684600063ffffffff611e0616565b6110386001600160a01b038516848463ffffffff611e0616565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611ab557508115155b949350505050565b836001600160a01b0316856001600160a01b03161415611adc576110f5565b611aef816208000063ffffffff61184616565b1515611b0582634000000063ffffffff61184616565b15151415611df9576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611c3357604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611b8b57600080fd5b505afa158015611b9f573d6000803e3d6000fd5b505050506040513d6020811015611bb557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b50505050611c2e73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585611f19565b6110f5565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611cb157604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611b8b57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611d6457611cf78573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611abd565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d4657600080fd5b505af1158015611d5a573d6000803e3d6000fd5b50505050506110f5565b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611df957611daa8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611abd565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d4657600080fd5b6110f58585858585611f19565b801580611e8c575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611e5e57600080fd5b505afa158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5051155b611ec75760405162461bcd60e51b815260040180806020018281038252603681526020018061477e6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526115f290849061168e565b6110f585858585855b611f35816280000063ffffffff61184616565b15611f4a82634000000063ffffffff61184616565b15141561239c57611f59614695565b611f616123a9565b905060005b600881101561213457818160088110611f7b57fe5b60200201516001600160a01b0316876001600160a01b0316141561212c576000828260088110611fa757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611fe457600080fd5b505afa158015611ff8573d6000803e3d6000fd5b505050506040513d602081101561200e57600080fd5b50519050600083836008811061202057fe5b60200201516001600160a01b031663c85c93aa8860016000604051908082528060200260200182016040528015612061578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156120c15781810151838201526020016120a9565b50505050905001945050505050602060405180830381600087803b1580156120e857600080fd5b505af11580156120fc573d6000803e3d6000fd5b505050506040513d602081101561211257600080fd5b505190506121238289838989611f22565b505050506110f5565b600101611f66565b5060005b60088110156123995781816008811061214d57fe5b60200201516001600160a01b0316866001600160a01b0316141561239157600082826008811061217957fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156121b657600080fd5b505afa1580156121ca573d6000803e3d6000fd5b505050506040513d60208110156121e057600080fd5b505190506121f1888288888861248f565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561223b57600080fd5b505afa15801561224f573d6000803e3d6000fd5b505050506040513d602081101561226557600080fd5b5051905061229484846008811061227857fe5b60200201516001600160a01b038416908363ffffffff61198d16565b8383600881106122a057fe5b60200201516001600160a01b0316633cfcef648260006040519080825280602002602001820160405280156122df578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561233557818101518382015260200161231d565b505050509050019350505050602060405180830381600087803b15801561235b57600080fd5b505af115801561236f573d6000803e3d6000fd5b505050506040513d602081101561238557600080fd5b506110f5945050505050565b600101612138565b50505b6110f5858585858561248f565b6123b1614695565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b6110f585858585855b836001600160a01b0316856001600160a01b031614156124b7576110f5565b6124c98161080063ffffffff61184616565b15156124df82634000000063ffffffff61184616565b1515141561287a576124ef6146b4565b6124f7612887565b905060005b600d8110156126b4578181600d811061251157fe5b60200201516001600160a01b0316876001600160a01b031614156126ac5760008282600d811061253d57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561257a57600080fd5b505afa15801561258e573d6000803e3d6000fd5b505050506040513d60208110156125a457600080fd5b505190508282600d81106125b457fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156125fe57600080fd5b505af1158015612612573d6000803e3d6000fd5b505050506126a48188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561267157600080fd5b505afa158015612685573d6000803e3d6000fd5b505050506040513d602081101561269b57600080fd5b50518888612498565b5050506110f5565b6001016124fc565b5060005b600d811015612877578181600d81106126cd57fe5b60200201516001600160a01b0316866001600160a01b0316141561286f5760008282600d81106126f957fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561273657600080fd5b505afa15801561274a573d6000803e3d6000fd5b505050506040513d602081101561276057600080fd5b5051905061277188828888886129f4565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156127bb57600080fd5b505afa1580156127cf573d6000803e3d6000fd5b505050506040513d60208110156127e557600080fd5b505190506127f88484600d811061227857fe5b8383600d811061280457fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561284e57600080fd5b505af1158015612862573d6000803e3d6000fd5b50505050505050506110f5565b6001016126b8565b50505b6110f585858585856129f4565b61288f6146b4565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b6110f585858585855b836001600160a01b0316856001600160a01b03161415612a1c576110f5565b612a2d81601063ffffffff61184616565b1515612a4382634000000063ffffffff61184616565b15151415612cd15760408051639bbde94760e01b81526001600160a01b0387166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b158015612aa957600080fd5b505afa158015612abd573d6000803e3d6000fd5b505050506040513d6020811015612ad357600080fd5b505190506001600160a01b03811615612b8a57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612b2c57600080fd5b505af1158015612b40573d6000803e3d6000fd5b505050506040513d6020811015612b5657600080fd5b5060009050612b746001600160a01b0383163063ffffffff61103e16565b9050612b8382878387876129fd565b50506110f5565b60408051639bbde94760e01b81526001600160a01b0387166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b158015612be457600080fd5b505afa158015612bf8573d6000803e3d6000fd5b505050506040513d6020811015612c0e57600080fd5b505190506001600160a01b03811615612ccf57612c2e8682868686612cda565b6000612c496001600160a01b0383163063ffffffff61103e16565b9050612c5d826001600160a01b031661117a565b156114fd57734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612cb157600080fd5b505af1158015612cc5573d6000803e3d6000fd5b5050505050612b83565b505b6110f585858585855b6110f58585858585836001600160a01b0316856001600160a01b03161415612d01576110f5565b612d1281602063ffffffff61184616565b1515612d2882634000000063ffffffff61184616565b15151415612fcf576000612d3b86612fdc565b90506001600160a01b0380821614612e8b57612d5f816001600160a01b031661117a565b15612de5576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b158015612db357600080fd5b505af1158015612dc7573d6000803e3d6000fd5b505050506040513d6020811015612ddd57600080fd5b50612e619050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b158015612e3457600080fd5b505af1158015612e48573d6000803e3d6000fd5b505050506040513d6020811015612e5e57600080fd5b50505b6000612e7c6001600160a01b0383163063ffffffff61103e16565b9050612b838287838787613352565b612e9485612fdc565b90506001600160a01b0380821614612fcd57612eb38682868686613352565b6000612ece6001600160a01b0383163063ffffffff61103e16565b9050612ee2826001600160a01b031661117a565b15612f645760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b158015612f3157600080fd5b505af1158015612f45573d6000803e3d6000fd5b50505050506040513d6020811015612f5c57600080fd5b50612b839050565b612f7e6001600160a01b038316878363ffffffff61198d16565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b15801561155d57600080fd5b505b6110f58585858585613352565b6000612ff0826001600160a01b031661117a565b15612ffe57506000196111b1565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b602083106130695780518252601f19909201916020918201910161304a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d80600081146130ca576040519150601f19603f3d011682016040523d82523d6000602084013e6130cf565b606091505b5091509150816130e557600019925050506111b1565b6000805b825181600601101561323e5782816000018151811061310457fe5b6020910101516001600160f81b031916602360f91b148015613147575082816001018151811061313057fe5b6020910101516001600160f81b031916607560f81b145b8015613174575082816002018151811061315d57fe5b6020910101516001600160f81b031916601b60fa1b145b80156131a1575082816003018151811061318a57fe5b6020910101516001600160f81b031916606360f81b145b80156131ce57508281600401815181106131b757fe5b6020910101516001600160f81b031916603960f91b145b80156131fb57508281600501815181106131e457fe5b6020910101516001600160f81b031916607560f81b145b8015613228575082816006018151811061321157fe5b6020910101516001600160f81b031916606d60f81b145b15613236576001915061323e565b6001016130e9565b50806132515760001993505050506111b1565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b602083106132b45780518252601f199092019160209182019101613295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613315576040519150601f19603f3d011682016040523d82523d6000602084013e61331a565b606091505b509093509150826133325760001993505050506111b1565b81806020019051602081101561334757600080fd5b505195945050505050565b6110f585858585855b836001600160a01b0316856001600160a01b0316141561337a576110f5565b61338b81608063ffffffff61184616565b15156133a182634000000063ffffffff61184616565b151514156136eb57604080516354732ba160e11b81526001600160a01b0387166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b15801561340757600080fd5b505afa15801561341b573d6000803e3d6000fd5b505050506040513d602081101561343157600080fd5b505190506001600160a01b038116156134b557856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561348a57600080fd5b505af115801561349e573d6000803e3d6000fd5b505050506134af818686868661335b565b506110f5565b604080516354732ba160e11b81526001600160a01b0387166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b15801561350f57600080fd5b505afa158015613523573d6000803e3d6000fd5b505050506040513d602081101561353957600080fd5b505190506001600160a01b038116156136e95761355986828686866136f4565b60006135746001600160a01b0383163063ffffffff61103e16565b905061360973398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b1580156135c657600080fd5b505afa1580156135da573d6000803e3d6000fd5b505050506040513d60208110156135f057600080fd5b50516001600160a01b038416908363ffffffff61198d16565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666136356001600160a01b03851661117a565b613640576000613642565b825b613654856001600160a01b031661117a565b61365e5784613674565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b1580156136c957600080fd5b505af11580156136dd573d6000803e3d6000fd5b505050505050506110f5565b505b6110f585858585855b836001600160a01b0316856001600160a01b03161415613713576110f5565b6137258161040063ffffffff61184616565b151561373b82634000000063ffffffff61184616565b15151415613a12576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e814156138c857736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156137c257600080fd5b505af11580156137d6573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b15801561382f57600080fd5b505afa158015613843573d6000803e3d6000fd5b505050506040513d602081101561385957600080fd5b5051905080156138ad57606061388773b683d83a532e2cb7dfa5275eed3698436371cc9f878460018761078d565b9150506138ab73b683d83a532e2cb7dfa5275eed3698436371cc9f878484876110e8565b505b6134af60008051602061470983398151915286868686613a1b565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613a125761390885600080516020614709833981519152858585613a1b565b604080516370a0823160e01b81523060048201529051600091600080516020614709833981519152916370a0823191602480820192602092909190829003018186803b15801561395757600080fd5b505afa15801561396b573d6000803e3d6000fd5b505050506040513d602081101561398157600080fd5b505190506139b8600080516020614709833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff61198d16565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611d4657600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b03161415613a3a576110f5565b613a4b81604063ffffffff61184616565b1515613a6182634000000063ffffffff61184616565b15151415613ccf576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2151415613b86576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b158015613ae757600080fd5b505af1158015613afb573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051611c2e93506000805160206147098339815191529250879183916370a0823191602480820192602092909190829003018186803b158015613b5357600080fd5b505afa158015613b67573d6000803e3d6000fd5b505050506040513d6020811015613b7d57600080fd5b50518585613cd8565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c2151415613ccf57613bc685600080516020614709833981519152858585613cd8565b604080516370a0823160e01b81523060048201529051600091600080516020614709833981519152916370a0823191602480820192602092909190829003018186803b158015613c1557600080fd5b505afa158015613c29573d6000803e3d6000fd5b505050506040513d6020811015613c3f57600080fd5b50519050613c766000805160206147098339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff61198d16565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611d4657600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b03161415613cf7576110f5565b613d0d816502000000000063ffffffff61184616565b1515613d2382634000000063ffffffff61184616565b15151415614523576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a51415614266576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481480613d9157506001600160a01b038416600080516020614709833981519152145b80613db857506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b80613dda57506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b15613fda5760408051633b3fb85360e21b81526001600160a01b03878116600483015260248201869052861660448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b158015613e4b57600080fd5b505afa158015613e5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015613e8857600080fd5b815160208301805160405192949293830192919084600160201b821115613eae57600080fd5b908301906020820185811115613ec357600080fd5b8251600160201b811182820188101715613edc57600080fd5b82525081516020918201929091019080838360005b83811015613f09578181015183820152602001613ef1565b50505050905090810190601f168015613f365780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b83526001600160a01b038d16600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b158015613fa757600080fd5b505af1158015613fbb573d6000803e3d6000fd5b505050506040513d6020811015613fd157600080fd5b50611c2e915050565b60408051633b3fb85360e21b81526001600160a01b03871660048201526024810185905260008051602061470983398151915260448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b15801561405257600080fd5b505afa158015614066573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561408f57600080fd5b815160208301805160405192949293830192919084600160201b8211156140b557600080fd5b9083019060208201858111156140ca57600080fd5b8251600160201b8111828201881017156140e357600080fd5b82525081516020918201929091019080838360005b838110156141105781810151838201526020016140f8565b50505050905090810190601f16801561413d5780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b8352600080516020614709833981519152600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b1580156141b357600080fd5b505af11580156141c7573d6000803e3d6000fd5b505050506040513d60208110156141dd57600080fd5b5050604080516370a0823160e01b815230600482015290516134af9160008051602061470983398151915291889183916370a0823191602480820192602092909190829003018186803b15801561423357600080fd5b505afa158015614247573d6000803e3d6000fd5b505050506040513d602081101561425d57600080fd5b5051868661452c565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415614523576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806142cc57506001600160a01b038516600080516020614709833981519152145b806142f357506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b8061431557506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b156143eb576143486001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff61198d16565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b1580156143b957600080fd5b505af11580156143cd573d6000803e3d6000fd5b505050506040513d60208110156143e357600080fd5b50611c2e9050565b6144068560008051602061470983398151915285858561452c565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160008051602061470983398151915291889183916370a08231916024808301926020929190829003018186803b15801561447157600080fd5b505afa158015614485573d6000803e3d6000fd5b505050506040513d602081101561449b57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b1580156144f957600080fd5b505af115801561450d573d6000803e3d6000fd5b505050506040513d6020811015612b8357600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b0316141561454b576110f5565b6110f58585858585600154614573906001600160a01b0387811691168563ffffffff61198d16565b6001546001600160a01b039081169063e2a7515e9061459390881661117a565b61459e5760006145a0565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015614638578181015183820152602001614620565b505050509050019750505050505050506020604051808303818588803b15801561466157600080fd5b505af1158015614675573d6000803e3d6000fd5b50505050506040513d602081101561468c57600080fd5b50505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a7231582082422d78f831c964d51b32a4a4d437609f95144f7415ad16456ffa44c296a85664736f6c634300051100320000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f50000000000000000000000009021c84f3900b610ab8625d26d739e3b7bff86ab
Deployed Bytecode
0x6080604052600436106100705760003560e01c80638373f2651161004e5780638373f26514610436578063c7851396146104ed578063e2a7515e146106b0578063fbe4ed951461077857610070565b8063085e2c5b1461007f57806343ee21f0146101295780637b33701a1461015a575b3332141561007d57600080fd5b005b34801561008b57600080fd5b506100ce600480360360a08110156100a257600080fd5b506001600160a01b0381358116916020810135909116906040810135906060810135906080013561078d565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156101145781810151838201526020016100fc565b50505050905001935050505060405180910390f35b34801561013557600080fd5b5061013e6107b0565b604080516001600160a01b039092168252519081900360200190f35b34801561016657600080fd5b50610396600480360360a081101561017d57600080fd5b810190602081018135600160201b81111561019757600080fd5b8201836020820111156101a957600080fd5b803590602001918460208302840111600160201b831117156101ca57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435959094909350604081019250602001359050600160201b81111561022157600080fd5b82018360208201111561023357600080fd5b803590602001918460208302840111600160201b8311171561025457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460208302840111600160201b831117156102d657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561032557600080fd5b82018360208201111561033757600080fd5b803590602001918460208302840111600160201b8311171561035857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506107bf945050505050565b604051808060200184815260200180602001838103835286818151815260200191508051906020019060200280838360005b838110156103e05781810151838201526020016103c8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561041f578181015183820152602001610407565b505050509050019550505050505060405180910390f35b34801561044257600080fd5b5061048b600480360360c081101561045957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a00135610a17565b6040518084815260200183815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156104d75781810151838201526020016104bf565b5050505090500194505050505060405180910390f35b61069e600480360360a081101561050357600080fd5b810190602081018135600160201b81111561051d57600080fd5b82018360208201111561052f57600080fd5b803590602001918460208302840111600160201b8311171561055057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135600160201b8111156105ab57600080fd5b8201836020820111156105bd57600080fd5b803590602001918460208302840111600160201b831117156105de57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561062d57600080fd5b82018360208201111561063f57600080fd5b803590602001918460208302840111600160201b8311171561066057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610b6e945050505050565b60408051918252519081900360200190f35b61069e600480360360c08110156106c657600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b81111561070557600080fd5b82018360208201111561071757600080fd5b803590602001918460208302840111600160201b8311171561073857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505091359250610db1915050565b34801561078457600080fd5b5061013e610ead565b600060606107a087878787876000610a17565b9199919850909650505050505050565b6001546001600160a01b031681565b6060600060608060018951036040519080825280602002602001820160405280156107f4578160200160208202803883390190505b50935060015b8951811015610a0a5789818151811061080f57fe5b60200260200101516001600160a01b03168a600183038151811061082f57fe5b60200260200101516001600160a01b0316141561088c578060011461086a5784600282038151811061085d57fe5b602002602001015161086c565b885b85600183038151811061087b57fe5b602002602001018181525050610a02565b60608a90506109268160018403815181106108a357fe5b60200260200101518284815181106108b757fe5b6020026020010151846001146108e3578860028603815181106108d657fe5b60200260200101516108e5565b8c5b8c86815181106108f157fe5b60200260200101518c878151811061090557fe5b60200260200101518c888151811061091957fe5b6020026020010151610a17565b88600186038151811061093557fe5b60209081029190910101929092529a509250610957858b63ffffffff610ebc16565b945083516000141561099257825160405190808252806020026020018201604052801561098e578160200160208202803883390190505b5093505b60005b84518110156109ff576109e0600184036008028583815181106109b457fe5b6020026020010151901b8683815181106109ca57fe5b6020026020010151610ebc90919063ffffffff16565b8582815181106109ec57fe5b6020908102919091010152600101610995565b50505b6001016107fa565b5050955095509592505050565b6000805460408051638373f26560e01b81526001600160a01b038a81166004830152898116602483015260448201899052606482018890526084820187905260a48201869052915184936060931691638373f2659160c48083019287929190829003018186803b158015610a8a57600080fd5b505afa158015610a9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015610ac757600080fd5b81516020830151604080850180519151939592948301929184600160201b821115610af157600080fd5b908301906020820185811115610b0657600080fd5b82518660208202830111600160201b82111715610b2257600080fd5b82525081516020918201928201910280838360005b83811015610b4f578181015183820152602001610b37565b5050505090500160405250505092509250925096509650969350505050565b6000610ba433308789600081518110610b8357fe5b60200260200101516001600160a01b0316610f1f909392919063ffffffff16565b610bd43087600081518110610bb557fe5b60200260200101516001600160a01b031661103e90919063ffffffff16565b905060015b8651811015610d5257868181518110610bee57fe5b60200260200101516001600160a01b0316876001830381518110610c0e57fe5b60200260200101516001600160a01b03161415610c2a57610d4a565b60608451604051908082528060200260200182016040528015610c57578160200160208202803883390190505b50905060005b8551811015610ca55760018303600802868281518110610c7957fe5b6020026020010151901c60ff16828281518110610c9257fe5b6020908102919091010152600101610c5d565b50610cef886001840381518110610cb857fe5b6020026020010151898481518110610ccc57fe5b60200260200101518584888781518110610ce257fe5b60200260200101516110e8565b610cff30898481518110610bb557fe5b9250610d4733610d18308b6001870381518110610bb557fe5b8a6001860381518110610d2757fe5b60200260200101516001600160a01b03166110fc9092919063ffffffff16565b50505b600101610bd9565b5083811015610d925760405162461bcd60e51b81526004018080602001828103825260358152602001806146d46035913960400191505060405180910390fd5b610da733828860018a510381518110610d2757fe5b5095945050505050565b6000610dce6001600160a01b03881633308863ffffffff610f1f16565b6000610de96001600160a01b0389163063ffffffff61103e16565b9050610df888888387876110e8565b610e116001600160a01b0388163063ffffffff61103e16565b915084821015610e525760405162461bcd60e51b81526004018080602001828103825260358152602001806146d46035913960400191505060405180910390fd5b610e6c6001600160a01b038816338463ffffffff6110fc16565b50610ea133610e8a6001600160a01b038b163063ffffffff61103e16565b6001600160a01b038b16919063ffffffff6110fc16565b50509695505050505050565b6000546001600160a01b031681565b600082820183811015610f16576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b80610f2957611038565b610f328461117a565b1561101d576001600160a01b03831633148015610f4f5750803410155b610f8a5760405162461bcd60e51b815260040180806020018281038252602b815260200180614729602b913960400191505060405180910390fd5b6001600160a01b0382163014610fd2576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610fd0573d6000803e3d6000fd5b505b8034111561101857336108fc610fee348463ffffffff6111b616565b6040518115909202916000818181858888f19350505050158015611016573d6000803e3d6000fd5b505b611038565b6110386001600160a01b03851684848463ffffffff6111f816565b50505050565b60006110498361117a565b1561105f57506001600160a01b03811631610f19565b826001600160a01b03166370a08231836040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156110b557600080fd5b505afa1580156110c9573d6000803e3d6000fd5b505050506040513d60208110156110df57600080fd5b50519050610f19565b6110f58585858585611252565b5050505050565b60008161110b57506001611173565b6111148461117a565b15611155576040516001600160a01b0384169083156108fc029084906000818181858888f1935050505015801561114f573d6000803e3d6000fd5b50611173565b61116f6001600160a01b038516848463ffffffff6115a016565b5060015b9392505050565b60006001600160a01b03821615806111ae57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b90505b919050565b6000610f1683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506115f7565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261103890859061168e565b836001600160a01b0316856001600160a01b03161415611271576110f5565b611287816508000000000063ffffffff61184616565b151561129d82634000000063ffffffff61184616565b151514156115935760006112b08661184c565b90506001600160a01b038082161461143857856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561130857600080fd5b505af115801561131c573d6000803e3d6000fd5b505050506040513d602081101561133257600080fd5b50600090506113506001600160a01b0383163063ffffffff61103e16565b90506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214156113ea5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156113d157600080fd5b505af11580156113e5573d6000803e3d6000fd5b505050505b6114366001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214611417578261142d565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b87838787611252565b505b6114418561184c565b90506001600160a01b03808216146115915761149f866001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146114815782611497565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b868686611980565b60006114fa306001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2146114cf57836114e5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03169063ffffffff61103e16565b90505b6115176001600160a01b038316878363ffffffff61198d16565b856001600160a01b031663a0712d68826040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b15801561155d57600080fd5b505af1158015611571573d6000803e3d6000fd5b505050506040513d602081101561158757600080fd5b506110f592505050565b505b6110f58585858585611980565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526115f290849061168e565b505050565b600081848411156116865760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561164b578181015183820152602001611633565b50505050905090810190601f1680156116785780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6116a0826001600160a01b0316611a81565b6116f1576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b6020831061172f5780518252601f199092019160209182019101611710565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611791576040519150601f19603f3d011682016040523d82523d6000602084013e611796565b606091505b5091509150816117ed576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156110385780806020019051602081101561180957600080fd5b50516110385760405162461bcd60e51b815260040180806020018281038252602a815260200180614754602a913960400191505060405180910390fd5b16151590565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166330df135f60e21b178152915181516000938493606093734cb120dd1d33c9a3de8bc15620c7cd43418d77e293919290918291908083835b602083106118da5780518252601f1990920191602091820191016118bb565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461193a576040519150601f19603f3d011682016040523d82523d6000602084013e61193f565b606091505b509150915081158061195057508051155b1561196157600019925050506111b1565b80806020019051602081101561197657600080fd5b5051949350505050565b6110f58585858585611abd565b6119968361117a565b6115f257806119bf576119ba6001600160a01b03841683600063ffffffff611e0616565b6115f2565b60408051636eb1769f60e11b81523060048201526001600160a01b038481166024830152915160009286169163dd62ed3e916044808301926020929190829003018186803b158015611a1057600080fd5b505afa158015611a24573d6000803e3d6000fd5b505050506040513d6020811015611a3a57600080fd5b5051905081811015611038578015611a6757611a676001600160a01b03851684600063ffffffff611e0616565b6110386001600160a01b038516848463ffffffff611e0616565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611ab557508115155b949350505050565b836001600160a01b0316856001600160a01b03161415611adc576110f5565b611aef816208000063ffffffff61184616565b1515611b0582634000000063ffffffff61184616565b15151415611df9576001600160a01b03851673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611c3357604080516370a0823160e01b8152306004820152905173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611b8b57600080fd5b505afa158015611b9f573d6000803e3d6000fd5b505050506040513d6020811015611bb557600080fd5b5051604080516001600160e01b031960e085901b168152600481019290925251602480830192600092919082900301818387803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b50505050611c2e73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85858585611f19565b6110f5565b6001600160a01b03851673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611cb157604080516370a0823160e01b8152306004820152905173c0829421c1d260bd3cb3e0f06cfe2d52db2ce31591632e1a7d4d9183916370a08231916024808301926020929190829003018186803b158015611b8b57600080fd5b6001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611d6457611cf78573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611abd565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d4657600080fd5b505af1158015611d5a573d6000803e3d6000fd5b50505050506110f5565b6001600160a01b03841673c0829421c1d260bd3cb3e0f06cfe2d52db2ce3151415611df957611daa8573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee858585611abd565b73c0829421c1d260bd3cb3e0f06cfe2d52db2ce3156001600160a01b031663d0e30db0476040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d4657600080fd5b6110f58585858585611f19565b801580611e8c575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611e5e57600080fd5b505afa158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5051155b611ec75760405162461bcd60e51b815260040180806020018281038252603681526020018061477e6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526115f290849061168e565b6110f585858585855b611f35816280000063ffffffff61184616565b15611f4a82634000000063ffffffff61184616565b15141561239c57611f59614695565b611f616123a9565b905060005b600881101561213457818160088110611f7b57fe5b60200201516001600160a01b0316876001600160a01b0316141561212c576000828260088110611fa757fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611fe457600080fd5b505afa158015611ff8573d6000803e3d6000fd5b505050506040513d602081101561200e57600080fd5b50519050600083836008811061202057fe5b60200201516001600160a01b031663c85c93aa8860016000604051908082528060200260200182016040528015612061578160200160208202803883390190505b506040518463ffffffff1660e01b8152600401808481526020018315151515815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156120c15781810151838201526020016120a9565b50505050905001945050505050602060405180830381600087803b1580156120e857600080fd5b505af11580156120fc573d6000803e3d6000fd5b505050506040513d602081101561211257600080fd5b505190506121238289838989611f22565b505050506110f5565b600101611f66565b5060005b60088110156123995781816008811061214d57fe5b60200201516001600160a01b0316866001600160a01b0316141561239157600082826008811061217957fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156121b657600080fd5b505afa1580156121ca573d6000803e3d6000fd5b505050506040513d60208110156121e057600080fd5b505190506121f1888288888861248f565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561223b57600080fd5b505afa15801561224f573d6000803e3d6000fd5b505050506040513d602081101561226557600080fd5b5051905061229484846008811061227857fe5b60200201516001600160a01b038416908363ffffffff61198d16565b8383600881106122a057fe5b60200201516001600160a01b0316633cfcef648260006040519080825280602002602001820160405280156122df578160200160208202803883390190505b506040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561233557818101518382015260200161231d565b505050509050019350505050602060405180830381600087803b15801561235b57600080fd5b505af115801561236f573d6000803e3d6000fd5b505050506040513d602081101561238557600080fd5b506110f5945050505050565b600101612138565b50505b6110f5858585858561248f565b6123b1614695565b5060408051610100810182527378751b12da02728f467a44eac40f5cbc16bd793481527312b98c621e8754ae70d0fdbbc73d6208bc3e3ca660208201527363d27b3da94a9e871222cb0a32232674b02d2f2d91810191909152731846bdfdb6a0f5c473dec610144513bd071999fb606082015273cddb1bceb7a1979c6caa0229820707429dd3ec6c60808201527342740698959761baf1b06baa51efbd88cb1d862b60a08201527310ec0d497824e342bcb0edce00959142aaa766dd60c082015273eb66acc3d011056b00ea521f8203580c2e5d399160e082015290565b6110f585858585855b836001600160a01b0316856001600160a01b031614156124b7576110f5565b6124c98161080063ffffffff61184616565b15156124df82634000000063ffffffff61184616565b1515141561287a576124ef6146b4565b6124f7612887565b905060005b600d8110156126b4578181600d811061251157fe5b60200201516001600160a01b0316876001600160a01b031614156126ac5760008282600d811061253d57fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561257a57600080fd5b505afa15801561258e573d6000803e3d6000fd5b505050506040513d60208110156125a457600080fd5b505190508282600d81106125b457fe5b60200201516001600160a01b0316632e1a7d4d876040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156125fe57600080fd5b505af1158015612612573d6000803e3d6000fd5b505050506126a48188836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561267157600080fd5b505afa158015612685573d6000803e3d6000fd5b505050506040513d602081101561269b57600080fd5b50518888612498565b5050506110f5565b6001016124fc565b5060005b600d811015612877578181600d81106126cd57fe5b60200201516001600160a01b0316866001600160a01b0316141561286f5760008282600d81106126f957fe5b60200201516001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561273657600080fd5b505afa15801561274a573d6000803e3d6000fd5b505050506040513d602081101561276057600080fd5b5051905061277188828888886129f4565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b1580156127bb57600080fd5b505afa1580156127cf573d6000803e3d6000fd5b505050506040513d60208110156127e557600080fd5b505190506127f88484600d811061227857fe5b8383600d811061280457fe5b60200201516001600160a01b031663b6b55f25826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561284e57600080fd5b505af1158015612862573d6000803e3d6000fd5b50505050505050506110f5565b6001016126b8565b50505b6110f585858585856129f4565b61288f6146b4565b50604080516101a0810182527316de59092dae5ccf4a1e6439d611fd0653f0bd0181527304aa51bbcb46541455ccf1b8bef2ebc5d3787ec960208201527373a052500105205d34daf004eab301916da8190f918101919091527383f798e925bcd4017eb265844fddabb448f1707d606082015273d6ad7a6750a7593e092a9b218d66c0a814a3436e608082015273f61718057901f84c4eec4339ef8f0d86d2b4560060a08201527304bc0ab673d88ae9dbc9da2380cb6b79c4bca9ae60c082015273c2cb1040220768554cf699b0d863a3cd4324ce3260e082015273e6354ed5bc4b393a5aad09f21c46e101e692d4476101008201527326ea744e5b887e5205727f55dfbe8685e3b219516101208201527399d1fa417f94dcd62bfe781a1213c092a47041bc610140820152739777d7e2b60bb01759d0e2f8be2095df444cb07e610160820152731be5d71f2da660bfdee8012ddc58d024448a0a5961018082015290565b6110f585858585855b836001600160a01b0316856001600160a01b03161415612a1c576110f5565b612a2d81601063ffffffff61184616565b1515612a4382634000000063ffffffff61184616565b15151415612cd15760408051639bbde94760e01b81526001600160a01b0387166004820152905160009173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde94791602480820192602092909190829003018186803b158015612aa957600080fd5b505afa158015612abd573d6000803e3d6000fd5b505050506040513d6020811015612ad357600080fd5b505190506001600160a01b03811615612b8a57856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015612b2c57600080fd5b505af1158015612b40573d6000803e3d6000fd5b505050506040513d6020811015612b5657600080fd5b5060009050612b746001600160a01b0383163063ffffffff61103e16565b9050612b8382878387876129fd565b50506110f5565b60408051639bbde94760e01b81526001600160a01b0387166004820152905173f451dbd7ba14bfa7b1b78a766d3ed438f79ee1d191639bbde947916024808301926020929190829003018186803b158015612be457600080fd5b505afa158015612bf8573d6000803e3d6000fd5b505050506040513d6020811015612c0e57600080fd5b505190506001600160a01b03811615612ccf57612c2e8682868686612cda565b6000612c496001600160a01b0383163063ffffffff61103e16565b9050612c5d826001600160a01b031661117a565b156114fd57734ddc2d193948926d02f9b1fe9e1daa0718270ed56001600160a01b0316631249c58b826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612cb157600080fd5b505af1158015612cc5573d6000803e3d6000fd5b5050505050612b83565b505b6110f585858585855b6110f58585858585836001600160a01b0316856001600160a01b03161415612d01576110f5565b612d1281602063ffffffff61184616565b1515612d2882634000000063ffffffff61184616565b15151415612fcf576000612d3b86612fdc565b90506001600160a01b0380821614612e8b57612d5f816001600160a01b031661117a565b15612de5576040805163081a6b2560e41b81523060048201526024810186905290516001600160a01b038816916381a6b2509160448083019260209291908290030181600087803b158015612db357600080fd5b505af1158015612dc7573d6000803e3d6000fd5b505050506040513d6020811015612ddd57600080fd5b50612e619050565b60408051632770a7eb60e21b81523060048201526024810186905290516001600160a01b03881691639dc29fac9160448083019260209291908290030181600087803b158015612e3457600080fd5b505af1158015612e48573d6000803e3d6000fd5b505050506040513d6020811015612e5e57600080fd5b50505b6000612e7c6001600160a01b0383163063ffffffff61103e16565b9050612b838287838787613352565b612e9485612fdc565b90506001600160a01b0380821614612fcd57612eb38682868686613352565b6000612ece6001600160a01b0383163063ffffffff61103e16565b9050612ee2826001600160a01b031661117a565b15612f645760408051638f6ede1f60e01b815230600482015290516001600160a01b03881691638f6ede1f91849160248082019260209290919082900301818588803b158015612f3157600080fd5b505af1158015612f45573d6000803e3d6000fd5b50505050506040513d6020811015612f5c57600080fd5b50612b839050565b612f7e6001600160a01b038316878363ffffffff61198d16565b604080516340c10f1960e01b81523060048201526024810183905290516001600160a01b038816916340c10f199160448083019260209291908290030181600087803b15801561155d57600080fd5b505b6110f58585858585613352565b6000612ff0826001600160a01b031661117a565b15612ffe57506000196111b1565b60408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b178152915181516000936060936001600160a01b0388169361138893919290918291908083835b602083106130695780518252601f19909201916020918201910161304a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d80600081146130ca576040519150601f19603f3d011682016040523d82523d6000602084013e6130cf565b606091505b5091509150816130e557600019925050506111b1565b6000805b825181600601101561323e5782816000018151811061310457fe5b6020910101516001600160f81b031916602360f91b148015613147575082816001018151811061313057fe5b6020910101516001600160f81b031916607560f81b145b8015613174575082816002018151811061315d57fe5b6020910101516001600160f81b031916601b60fa1b145b80156131a1575082816003018151811061318a57fe5b6020910101516001600160f81b031916606360f81b145b80156131ce57508281600401815181106131b757fe5b6020910101516001600160f81b031916603960f91b145b80156131fb57508281600501815181106131e457fe5b6020910101516001600160f81b031916607560f81b145b8015613228575082816006018151811061321157fe5b6020910101516001600160f81b031916606d60f81b145b15613236576001915061323e565b6001016130e9565b50806132515760001993505050506111b1565b60408051600481526024810182526020810180516001600160e01b031663797bf38560e01b178152915181516001600160a01b038916936113889392918291908083835b602083106132b45780518252601f199092019160209182019101613295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303818686fa925050503d8060008114613315576040519150601f19603f3d011682016040523d82523d6000602084013e61331a565b606091505b509093509150826133325760001993505050506111b1565b81806020019051602081101561334757600080fd5b505195945050505050565b6110f585858585855b836001600160a01b0316856001600160a01b0316141561337a576110f5565b61338b81608063ffffffff61184616565b15156133a182634000000063ffffffff61184616565b151514156136eb57604080516354732ba160e11b81526001600160a01b0387166004820152905160009173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e6574291602480820192602092909190829003018186803b15801561340757600080fd5b505afa15801561341b573d6000803e3d6000fd5b505050506040513d602081101561343157600080fd5b505190506001600160a01b038116156134b557856001600160a01b031663db006a75856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561348a57600080fd5b505af115801561349e573d6000803e3d6000fd5b505050506134af818686868661335b565b506110f5565b604080516354732ba160e11b81526001600160a01b0387166004820152905173ed8b133b7b88366e01bb9e38305ab11c265214949163a8e65742916024808301926020929190829003018186803b15801561350f57600080fd5b505afa158015613523573d6000803e3d6000fd5b505050506040513d602081101561353957600080fd5b505190506001600160a01b038116156136e95761355986828686866136f4565b60006135746001600160a01b0383163063ffffffff61103e16565b905061360973398ec7346dcd622edc5ae82352f02be94c62d1196001600160a01b031663f2f4eb266040518163ffffffff1660e01b815260040160206040518083038186803b1580156135c657600080fd5b505afa1580156135da573d6000803e3d6000fd5b505050506040513d60208110156135f057600080fd5b50516001600160a01b038416908363ffffffff61198d16565b73398ec7346dcd622edc5ae82352f02be94c62d11963d2d0e0666136356001600160a01b03851661117a565b613640576000613642565b825b613654856001600160a01b031661117a565b61365e5784613674565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b604080516001600160e01b031960e086901b1681526001600160a01b0390921660048301526024820186905261044d604483015251606480830192600092919082900301818588803b1580156136c957600080fd5b505af11580156136dd573d6000803e3d6000fd5b505050505050506110f5565b505b6110f585858585855b836001600160a01b0316856001600160a01b03161415613713576110f5565b6137258161040063ffffffff61184616565b151561373b82634000000063ffffffff61184616565b15151415613a12576001600160a01b038516736a4ffaafa8dd400676df8076ad6c724867b0e2e814156138c857736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b0316637f8661a1846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156137c257600080fd5b505af11580156137d6573d6000803e3d6000fd5b5050604080516370a0823160e01b815230600482015290516000935073b683d83a532e2cb7dfa5275eed3698436371cc9f92506370a0823191602480820192602092909190829003018186803b15801561382f57600080fd5b505afa158015613843573d6000803e3d6000fd5b505050506040513d602081101561385957600080fd5b5051905080156138ad57606061388773b683d83a532e2cb7dfa5275eed3698436371cc9f878460018761078d565b9150506138ab73b683d83a532e2cb7dfa5275eed3698436371cc9f878484876110e8565b505b6134af60008051602061470983398151915286868686613a1b565b6001600160a01b038416736a4ffaafa8dd400676df8076ad6c724867b0e2e81415613a125761390885600080516020614709833981519152858585613a1b565b604080516370a0823160e01b81523060048201529051600091600080516020614709833981519152916370a0823191602480820192602092909190829003018186803b15801561395757600080fd5b505afa15801561396b573d6000803e3d6000fd5b505050506040513d602081101561398157600080fd5b505190506139b8600080516020614709833981519152736a4ffaafa8dd400676df8076ad6c724867b0e2e88363ffffffff61198d16565b736a4ffaafa8dd400676df8076ad6c724867b0e2e86001600160a01b031663049878f3826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611d4657600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b03161415613a3a576110f5565b613a4b81604063ffffffff61184616565b1515613a6182634000000063ffffffff61184616565b15151415613ccf576001600160a01b0385167306af07097c9eeb7fd685c692751d5c66db49c2151415613b86576040805163ef693bed60e01b81523060048201526024810185905290517306af07097c9eeb7fd685c692751d5c66db49c2159163ef693bed91604480830192600092919082900301818387803b158015613ae757600080fd5b505af1158015613afb573d6000803e3d6000fd5b5050604080516370a0823160e01b81523060048201529051611c2e93506000805160206147098339815191529250879183916370a0823191602480820192602092909190829003018186803b158015613b5357600080fd5b505afa158015613b67573d6000803e3d6000fd5b505050506040513d6020811015613b7d57600080fd5b50518585613cd8565b6001600160a01b0384167306af07097c9eeb7fd685c692751d5c66db49c2151415613ccf57613bc685600080516020614709833981519152858585613cd8565b604080516370a0823160e01b81523060048201529051600091600080516020614709833981519152916370a0823191602480820192602092909190829003018186803b158015613c1557600080fd5b505afa158015613c29573d6000803e3d6000fd5b505050506040513d6020811015613c3f57600080fd5b50519050613c766000805160206147098339815191527306af07097c9eeb7fd685c692751d5c66db49c2158363ffffffff61198d16565b60408051633b4da69f60e01b81523060048201526024810183905290517306af07097c9eeb7fd685c692751d5c66db49c21591633b4da69f91604480830192600092919082900301818387803b158015611d4657600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b03161415613cf7576110f5565b613d0d816502000000000063ffffffff61184616565b1515613d2382634000000063ffffffff61184616565b15151415614523576001600160a01b03851673e2f2a5c287993345a840db3b0845fbc70f5935a51415614266576001600160a01b03841673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481480613d9157506001600160a01b038416600080516020614709833981519152145b80613db857506001600160a01b03841673dac17f958d2ee523a2206206994597c13d831ec7145b80613dda57506001600160a01b0384166e085d4780b73119b644ae5ecd22b376145b15613fda5760408051633b3fb85360e21b81526001600160a01b03878116600483015260248201869052861660448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b158015613e4b57600080fd5b505afa158015613e5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526060811015613e8857600080fd5b815160208301805160405192949293830192919084600160201b821115613eae57600080fd5b908301906020820185811115613ec357600080fd5b8251600160201b811182820188101715613edc57600080fd5b82525081516020918201929091019080838360005b83811015613f09578181015183820152602001613ef1565b50505050905090810190601f168015613f365780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b83526001600160a01b038d16600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b158015613fa757600080fd5b505af1158015613fbb573d6000803e3d6000fd5b505050506040513d6020811015613fd157600080fd5b50611c2e915050565b60408051633b3fb85360e21b81526001600160a01b03871660048201526024810185905260008051602061470983398151915260448201529051600091734c5e03065bc52cce84f3ac94df14bbac27eac89b9163ecfee14c916064808201928692909190829003018186803b15801561405257600080fd5b505afa158015614066573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052606081101561408f57600080fd5b815160208301805160405192949293830192919084600160201b8211156140b557600080fd5b9083019060208201858111156140ca57600080fd5b8251600160201b8111828201881017156140e357600080fd5b82525081516020918201929091019080838360005b838110156141105781810151838201526020016140f8565b50505050905090810190601f16801561413d5780820380516001836020036101000a031916815260200191505b5060408181526020928301516301e9a69560e41b8352600080516020614709833981519152600484015260248301819052905190975073e2f2a5c287993345a840db3b0845fbc70f5935a59650631e9a695095506044808301955092935091908290030181600087803b1580156141b357600080fd5b505af11580156141c7573d6000803e3d6000fd5b505050506040513d60208110156141dd57600080fd5b5050604080516370a0823160e01b815230600482015290516134af9160008051602061470983398151915291889183916370a0823191602480820192602092909190829003018186803b15801561423357600080fd5b505afa158015614247573d6000803e3d6000fd5b505050506040513d602081101561425d57600080fd5b5051868661452c565b6001600160a01b03841673e2f2a5c287993345a840db3b0845fbc70f5935a51415614523576001600160a01b03851673a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4814806142cc57506001600160a01b038516600080516020614709833981519152145b806142f357506001600160a01b03851673dac17f958d2ee523a2206206994597c13d831ec7145b8061431557506001600160a01b0385166e085d4780b73119b644ae5ecd22b376145b156143eb576143486001600160a01b03861673e2f2a5c287993345a840db3b0845fbc70f5935a58563ffffffff61198d16565b60408051631ba0488760e21b81526001600160a01b0387811660048301528616602482015260448101859052306064820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160848083019260209291908290030181600087803b1580156143b957600080fd5b505af11580156143cd573d6000803e3d6000fd5b505050506040513d60208110156143e357600080fd5b50611c2e9050565b6144068560008051602061470983398151915285858561452c565b604080516370a0823160e01b8152306004820152905173e2f2a5c287993345a840db3b0845fbc70f5935a591636e81221c9160008051602061470983398151915291889183916370a08231916024808301926020929190829003018186803b15801561447157600080fd5b505afa158015614485573d6000803e3d6000fd5b505050506040513d602081101561449b57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529290931660248301526044820152306064820152905160848083019260209291908290030181600087803b1580156144f957600080fd5b505af115801561450d573d6000803e3d6000fd5b505050506040513d6020811015612b8357600080fd5b6110f585858585855b836001600160a01b0316856001600160a01b0316141561454b576110f5565b6110f58585858585600154614573906001600160a01b0387811691168563ffffffff61198d16565b6001546001600160a01b039081169063e2a7515e9061459390881661117a565b61459e5760006145a0565b845b878787600088886040518863ffffffff1660e01b815260040180876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019060200280838360005b83811015614638578181015183820152602001614620565b505050509050019750505050505050506020604051808303818588803b15801561466157600080fd5b505af1158015614675573d6000803e3d6000fd5b50505050506040513d602081101561468c57600080fd5b50505050505050565b6040518061010001604052806008906020820280388339509192915050565b604051806101a00160405280600d90602082028038833950919291505056fe4f6e6553706c69743a2061637475616c2072657475726e20616d6f756e74206973206c657373207468616e206d696e52657475726e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f57726f6e6720757365616765206f66204554482e756e6976657273616c5472616e7366657246726f6d28295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a265627a7a7231582082422d78f831c964d51b32a4a4d437609f95144f7415ad16456ffa44c296a85664736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f50000000000000000000000009021c84f3900b610ab8625d26d739e3b7bff86ab
-----Decoded View---------------
Arg [0] : _oneSplitView (address): 0x4CE45D9E8DD0dAA59DBA328AE3e01b13f93B79F5
Arg [1] : _oneSplit (address): 0x9021C84f3900B610ab8625d26d739e3B7bFf86aB
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000004ce45d9e8dd0daa59dba328ae3e01b13f93b79f5
Arg [1] : 0000000000000000000000009021c84f3900b610ab8625d26d739e3b7bff86ab
Deployed Bytecode Sourcemap
185114:5910:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;185704:10;185718:9;185704:23;;185696:32;;;;;;185114:5910;185744:515;;8:9:-1;5:2;;;30:1;27;20:12;5:2;185744:515:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;185744: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;185744:515:0;;;;;;;;;;;;;;;;;;185409:25;;8:9:-1;5:2;;;30:1;27;20:12;5:2;185409:25:0;;;:::i;:::-;;;;-1:-1:-1;;;;;185409:25:0;;;;;;;;;;;;;;186902:1539;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186902:1539:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;186902:1539:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;186902:1539:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;186902:1539: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;186902:1539:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;186902:1539:0;;;;;;;;;-1:-1:-1;186902:1539:0;;;;-1:-1:-1;186902:1539:0;;;;-1:-1:-1;;;;5:28;;2:2;;;46:1;43;36:12;2:2;186902:1539:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;186902:1539: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;186902:1539:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;186902:1539:0;;;;;;;;-1:-1:-1;186902:1539:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;186902:1539:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;186902:1539: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;186902:1539:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;186902:1539:0;;;;;;;;-1:-1:-1;186902:1539:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;186902:1539:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;186902:1539: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;186902:1539:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;186902:1539:0;;-1:-1:-1;186902:1539:0;;-1:-1:-1;;;;;186902:1539: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;186902:1539: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;186902:1539:0;;;;;;;;;;;;;;;;;;;;186267:627;;8:9:-1;5:2;;;30:1;27;20:12;5:2;186267:627:0;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;186267: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;186267:627:0;;;;;;;;;;;;;;;;;;;189255:1302;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;189255:1302:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;189255:1302:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189255:1302: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;189255:1302:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;189255:1302:0;;;;;;;;;;;;-1:-1:-1;189255:1302:0;-1:-1:-1;189255:1302:0;;;;-1:-1:-1;189255:1302:0;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;189255:1302:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189255:1302: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;189255:1302:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;189255:1302:0;;;;;;;;-1:-1:-1;189255:1302:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;189255:1302:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;189255:1302: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;189255:1302:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;189255:1302:0;;-1:-1:-1;189255:1302:0;;-1:-1:-1;;;;;189255:1302:0:i;:::-;;;;;;;;;;;;;;;;188449:798;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;188449:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;188449:798:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;188449:798:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;188449:798:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;188449:798:0;;-1:-1:-1;;188449:798:0;;;-1:-1:-1;188449:798:0;;-1:-1:-1;;188449:798:0:i;185369:33::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;185369:33:0;;;:::i;185744:515::-;185966:20;186001:29;186091:160;186130:9;186154;186178:6;186199:5;186219;186239:1;186091:24;:160::i;:::-;186058:193;;;;-1:-1:-1;185744:515:0;;-1:-1:-1;;;;;;;185744:515:0:o;185409:25::-;;;-1:-1:-1;;;;;185409:25:0;;:::o;186902:1539::-;187192:30;187237:25;187277:29;187334:21;187414:1;187398:6;:13;:17;187384:32;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;187384:32:0;-1:-1:-1;187368:48:0;-1:-1:-1;187441:1:0;187427:1007;187448:6;:13;187444:1;:17;187427:1007;;;187504:6;187511:1;187504:9;;;;;;;;;;;;;;-1:-1:-1;;;;;187487:26:0;:6;187498:1;187494;:5;187487:13;;;;;;;;;;;;;;-1:-1:-1;;;;;187487:26:0;;187483:157;;;187558:1;187563;187558:6;187557:40;;187577:13;187595:1;187591;:5;187577:20;;;;;;;;;;;;;;187557:40;;;187568:6;187557:40;187534:13;187552:1;187548;:5;187534:20;;;;;;;;;;;;;:63;;;;;187616:8;;187483:157;187656:23;187682:6;187656:32;;187810:267;187853:7;187865:1;187861;:5;187853:14;;;;;;;;;;;;;;187886:7;187894:1;187886:10;;;;;;;;;;;;;;187916:1;187921;187916:6;187915:40;;187935:13;187953:1;187949;:5;187935:20;;;;;;;;;;;;;;187915:40;;;187926:6;187915:40;187974:5;187980:1;187974:8;;;;;;;;;;;;;;188001:5;188007:1;188001:8;;;;;;;;;;;;;;188028:31;188060:1;188028:34;;;;;;;;;;;;;;187810:24;:267::i;:::-;187724:13;187742:1;187738;:5;187724:20;;;;;;;;;;;;;;;;;187705:372;;;;;-1:-1:-1;187705:372:0;-1:-1:-1;188112:29:0;:17;187705:372;188112:29;:21;:29;:::i;:::-;188092:49;;188162:12;:19;188185:1;188162:24;188158:106;;;188236:4;:11;188222:26;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;188222:26:0;;188207:41;;188158:106;188283:6;188278:145;188299:12;:19;188295:1;:23;188278:145;;;188362:45;188403:1;188399;:5;188394:1;:11;188382:4;188387:1;188382:7;;;;;;;;;;;;;;:24;;188362:12;188375:1;188362:15;;;;;;;;;;;;;;:19;;:45;;;;:::i;:::-;188344:12;188357:1;188344:15;;;;;;;;;;;;;;;;;:63;188320:3;;188278:145;;;;187427:1007;;187463:3;;187427:1007;;;;186902:1539;;;;;;;;;;:::o;186267:627::-;186545:20;186684:12;;:202;;;-1:-1:-1;;;186684:202:0;;-1:-1:-1;;;;;186684:202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;186545:20;;186620:29;;186684:12;;:37;;:202;;;;;186545:20;;186684:202;;;;;;;:12;:202;;;5:2:-1;;;;30:1;27;20:12;5:2;186684:202:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;186684:202:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;186684: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;186684: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;186684:202:0;;421:4:-1;412:14;;;;186684:202:0;;;;;412:14:-1;186684: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;186684:202:0;;;;;;;;;;;186677:209;;;;;;186267:627;;;;;;;;;;:::o;189255:1302::-;189463:20;189496:66;189528:10;189548:4;189555:6;189496;189503:1;189496:9;;;;;;;;;;;;;;-1:-1:-1;;;;;189496:31:0;;;:66;;;;;;:::i;:::-;189590:43;189627:4;189590:6;189597:1;189590:9;;;;;;;;;;;;;;-1:-1:-1;;;;;189590:28:0;;;:43;;;;:::i;:::-;189575:58;-1:-1:-1;189658:1:0;189644:722;189665:6;:13;189661:1;:17;189644:722;;;189721:6;189728:1;189721:9;;;;;;;;;;;;;;-1:-1:-1;;;;;189704:26:0;:6;189715:1;189711;:5;189704:13;;;;;;;;;;;;;;-1:-1:-1;;;;;189704:26:0;;189700:75;;;189751:8;;189700:75;189791:21;189829:12;:19;189815:34;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;189815:34:0;-1:-1:-1;189791:58:0;-1:-1:-1;189869:6:0;189864:133;189885:12;:19;189881:1;:23;189864:133;;;189970:1;189966;:5;189961:1;:11;189941:12;189954:1;189941:15;;;;;;;;;;;;;;:32;;189977:4;189940:41;189930:4;189935:1;189930:7;;;;;;;;;;;;;;;;;:51;189906:3;;189864:133;;;;190013:161;190037:6;190048:1;190044;:5;190037:13;;;;;;;;;;;;;;190069:6;190076:1;190069:9;;;;;;;;;;;;;;190097:12;190128:4;190151:5;190157:1;190151:8;;;;;;;;;;;;;;190013:5;:161::i;:::-;190204:43;190241:4;190204:6;190211:1;190204:9;;;;;;;:43;190189:58;;190262:92;190294:10;190306:47;190347:4;190306:6;190317:1;190313;:5;190306:13;;;;;;;:47;190262:6;190273:1;190269;:5;190262:13;;;;;;;;;;;;;;-1:-1:-1;;;;;190262:31:0;;;:92;;;;;:::i;:::-;;189644:722;;189680:3;;189644:722;;;;190402:9;190386:12;:25;;190378:91;;;;-1:-1:-1;;;190378:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;190480:69;190524:10;190536:12;190480:6;190503:1;190487:6;:13;:17;190480:25;;;;;;;:69;;189255:1302;;;;;;;:::o;188449:798::-;188664:20;188697:66;-1:-1:-1;;;;;188697:31:0;;188729:10;188749:4;188756:6;188697:66;:31;:66;:::i;:::-;188774:17;188794:43;-1:-1:-1;;;;;188794:28:0;;188831:4;188794:43;:28;:43;:::i;:::-;188774:63;;188848:59;188854:9;188865;188876;188887:12;188901:5;188848;:59::i;:::-;188935:43;-1:-1:-1;;;;;188935:28:0;;188972:4;188935:43;:28;:43;:::i;:::-;188920:58;;189013:9;188997:12;:25;;188989:91;;;;-1:-1:-1;;;188989:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;189091:53;-1:-1:-1;;;;;189091:27:0;;189119:10;189131:12;189091:53;:27;:53;:::i;:::-;-1:-1:-1;189155:84:0;189183:10;189195:43;-1:-1:-1;;;;;189195:28:0;;189232:4;189195:43;:28;:43;:::i;:::-;-1:-1:-1;;;;;189155:27:0;;;:84;;:27;:84;:::i;:::-;;188449:798;;;;;;;;;:::o;185369:33::-;;;-1:-1:-1;;;;;185369:33:0;;:::o;12251:181::-;12309:7;12341:5;;;12365:6;;;;12357:46;;;;;-1:-1:-1;;;12357:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;12423:1;-1:-1:-1;12251:181:0;;;;;:::o;38184:617::-;38295:11;38291:50;;38323:7;;38291:50;38357:12;38363:5;38357;:12::i;:::-;38353:441;;;-1:-1:-1;;;;;38394:18:0;;38402:10;38394:18;:41;;;;;38429:6;38416:9;:19;;38394:41;38386:97;;;;-1:-1:-1;;;38386:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;38502:19:0;;38516:4;38502:19;38498:97;;38542:37;;-1:-1:-1;;;;;38542:29:0;;;:37;;;;;38572:6;;38542:37;;;;38572:6;38542:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38542:37:0;38498:97;38625:6;38613:9;:18;38609:101;;;38652:10;:42;38672:21;:9;38686:6;38672:21;:13;:21;:::i;:::-;38652:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38652:42:0;38609:101;38353:441;;;38742:40;-1:-1:-1;;;;;38742:22:0;;38765:4;38771:2;38775:6;38742:40;:22;:40;:::i;:::-;38184:617;;;;:::o;39786:228::-;39864:7;39888:12;39894:5;39888;:12::i;:::-;39884:123;;;-1:-1:-1;;;;;;39924:11:0;;;39917:18;;39884:123;39975:5;-1:-1:-1;;;;;39975:15:0;;39991:3;39975:20;;;;;;;;;;;;;-1:-1:-1;;;;;39975:20:0;-1:-1:-1;;;;;39975:20:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;39975:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39975:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39975:20:0;;-1:-1:-1;39968:27:0;;180367:328;180552:135;180575:9;180599;180623:6;180644:12;180671:5;180552:8;:135::i;:::-;180367:328;;;;;:::o;37828:348::-;37914:4;37935:11;37931:55;;-1:-1:-1;37970:4:0;37963:11;;37931:55;38002:12;38008:5;38002;:12::i;:::-;37998:171;;;38031:37;;-1:-1:-1;;;;;38031:29:0;;;:37;;;;;38061:6;;38031:37;;;;38061:6;38031:29;:37;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;38031:37:0;37998:171;;;38101:30;-1:-1:-1;;;;;38101:18:0;;38120:2;38124:6;38101:30;:18;:30;:::i;:::-;-1:-1:-1;38153:4:0;37998:171;37828:348;;;;;:::o;40604:166::-;40655:4;-1:-1:-1;;;;;40680:39:0;;;;:81;;-1:-1:-1;;;;;;40723:38:0;;37776:42;40723:38;40680:81;40672:90;;40604:166;;;;:::o;12707:136::-;12765:7;12792:43;12796:1;12799;12792:43;;;;;;;;;;;;;;;;;:3;:43::i;34483:204::-;34610:68;;;-1:-1:-1;;;;;34610:68:0;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;34610:68:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;34584:95:0;;34603:5;;34584:18;:95::i;180703:1928::-;180907:9;-1:-1:-1;;;;;180894:22:0;:9;-1:-1:-1;;;;;180894:22:0;;180890:61;;;180933:7;;180890:61;181013:29;:5;7796:13;181013:29;:11;:29;:::i;:::-;180967:75;;:42;:5;6679:10;180967:42;:11;:42;:::i;:::-;:75;;;180963:1503;;;181059:17;181079:33;181102:9;181079:22;:33::i;:::-;181059:53;-1:-1:-1;;;;;;181131:24:0;;;;181127:533;;181189:9;-1:-1:-1;;;;;181176:31:0;;181208:6;181176:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;181176:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;181176:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;181234:15:0;;-1:-1:-1;181252:44:0;-1:-1:-1;;;;;181252:29:0;;181290:4;181252:44;:29;:44;:::i;:::-;181234:62;-1:-1:-1;;;;;;181319:18:0;;48315:42;181319:18;181315:89;;;48315:42;-1:-1:-1;;;;;181362:13:0;;181376:7;181362:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;181362:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;181362:22:0;;;;181315:89;181422:222;-1:-1:-1;;;;;181454:18:0;;48315:42;181454:18;181453:47;;181490:10;181453:47;;;48103:42;181453:47;181523:9;181555:7;181585:12;181620:5;181422:8;:222::i;:::-;181127:533;;181689:33;181712:9;181689:22;:33::i;:::-;181676:46;-1:-1:-1;;;;;;181741:24:0;;;;181737:718;;181786:224;181820:9;-1:-1:-1;;;;;181853:18:0;;48315:42;181853:18;181852:47;;181889:10;181852:47;;;48103:42;181852:47;181922:6;181951:12;181986:5;181786:11;:224::i;:::-;182031:24;182058:83;182135:4;-1:-1:-1;;;;;182060:18:0;;48315:42;182060:18;182059:47;;182096:10;182059:47;;;48103:42;182059:47;-1:-1:-1;;;;;182058:68:0;;:83;:68;:83;:::i;:::-;182031:110;;182160:103;182283:65;-1:-1:-1;;;;;182283:27:0;;182319:9;182331:16;182283:65;:27;:65;:::i;:::-;182380:9;-1:-1:-1;;;;;182367:29:0;;182397:16;182367:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;182367:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182367:47:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;182433:7:0;;-1:-1:-1;;;182433:7:0;181737:718;180963:1503;;182485:138;182511:9;182535;182559:6;182580:12;182607:5;182485:11;:138::i;34299:176::-;34408:58;;;-1:-1:-1;;;;;34408:58:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;34408:58:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;34382:85:0;;34401:5;;34382:18;:85::i;:::-;34299:176;;;:::o;13180:192::-;13266:7;13302:12;13294:6;;;;13286:29;;;;-1:-1:-1;;;13286:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;13286:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;13338:5:0;;;13180:192::o;36338:1114::-;36942:27;36950:5;-1:-1:-1;;;;;36942:25:0;;:27::i;:::-;36934:71;;;;;-1:-1:-1;;;36934:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;37079:12;37093:23;37128:5;-1:-1:-1;;;;;37120:19:0;37140:4;37120:25;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;37120:25:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;37078:67:0;;;;37164:7;37156:52;;;;;-1:-1:-1;;;37156:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37225:17;;:21;37221:224;;37367:10;37356:30;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;37356:30:0;37348:85;;;;-1:-1:-1;;;37348:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47598:117;47689:12;47688:19;;;47598:117::o;176318:455::-;176490:128;;;-1:-1:-1;;;;;176490:128:0;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;176490:128:0;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;176441:188:0;;;;176386:6;;;;176420:17;;176266:42;;176490:128;;176441:188;;;;25:18:-1;176441:188:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;176441:188:0;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;176405:224:0;;;;176647:7;176646:8;:28;;;-1:-1:-1;176658:11:0;;:16;176646:28;176642:78;;;-1:-1:-1;;176691:17:0;;;;;;176642:78;176750:4;176739:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;176739:26:0;;176318:455;-1:-1:-1;;;;176318:455:0:o;167763:329::-;167948:136;167972:9;167996;168020:6;168041:12;168068:5;167948:9;:136::i;39260:518::-;39353:12;39359:5;39353;:12::i;:::-;39348:423;;39386:11;39382:101;;39418:24;-1:-1:-1;;;;;39418:17:0;;39436:2;39440:1;39418:24;:17;:24;:::i;:::-;39461:7;;39382:101;39519:34;;;-1:-1:-1;;;39519:34:0;;39543:4;39519:34;;;;-1:-1:-1;;;;;39519:34:0;;;;;;;;;39499:17;;39519:15;;;;;:34;;;;;;;;;;;;;;:15;:34;;;5:2:-1;;;;30:1;27;20:12;5:2;39519:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;39519:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;39519:34:0;;-1:-1:-1;39572:18:0;;;39568:192;;;39615:13;;39611:86;;39653:24;-1:-1:-1;;;;;39653:17:0;;39671:2;39675:1;39653:24;:17;:24;:::i;:::-;39715:29;-1:-1:-1;;;;;39715:17:0;;39733:2;39737:6;39715:29;:17;:29;:::i;31328:619::-;31388:4;31856:20;;31699:66;31896:23;;;;;;:42;;-1:-1:-1;31923:15:0;;;31896:42;31888:51;31328:619;-1:-1:-1;;;;31328:619:0:o;168100:1972::-;168305:9;-1:-1:-1;;;;;168292:22:0;:9;-1:-1:-1;;;;;168292:22:0;;168288:61;;;168331:7;;168288:61;168411:30;:5;5708:7;168411:30;:11;:30;:::i;:::-;168365:76;;:42;:5;6679:10;168365:42;:11;:42;:::i;:::-;:76;;;168361:1546;;;-1:-1:-1;;;;;168462:17:0;;48315:42;168462:17;168458:334;;;168514:29;;;-1:-1:-1;;;168514:29:0;;168537:4;168514:29;;;;;;48315:42;;168500:13;;48315:42;;168514:14;;:29;;;;;;;;;;;;;;48315:42;168514:29;;;5:2:-1;;;;30:1;27;20:12;5:2;168514:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;168514:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;168514:29:0;168500:44;;;-1:-1:-1;;;;;;168500:44:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;168500:44:0;;;;;;;-1:-1:-1;168500:44:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;168500:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;168500:44:0;;;;168563:188;48103:42;168631:9;168663:6;168692:12;168727:5;168563:11;:188::i;:::-;168770:7;;168458:334;-1:-1:-1;;;;;168812:29:0;;48228:42;168812:29;168808:370;;;168888:41;;;-1:-1:-1;;;168888:41:0;;168923:4;168888:41;;;;;;48228:42;;168862:25;;48228:42;;168888:26;;:41;;;;;;;;;;;;;;48228:42;168888:41;;;5:2:-1;;;;30:1;27;20:12;168808:370:0;-1:-1:-1;;;;;169198:17:0;;48315:42;169198:17;169194:331;;;169236:186;169268:9;48103:42;169334:6;169363:12;169398:5;169236:9;:186::i;:::-;48315:42;-1:-1:-1;;;;;169441:12:0;;169460:21;169441:43;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;169441:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169441:43:0;;;;;169503:7;;169194:331;-1:-1:-1;;;;;169545:29:0;;48228:42;169545:29;169541:355;;;169595:186;169627:9;48103:42;169693:6;169722:12;169757:5;169595:9;:186::i;:::-;48228:42;-1:-1:-1;;;;;169800:24:0;;169831:21;169800:55;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;169541:355:0;169926:138;169952:9;169976;170000:6;170021:12;170048:5;169926:11;:138::i;34695:621::-;35065:10;;;35064:62;;-1:-1:-1;35081:39:0;;;-1:-1:-1;;;35081:39:0;;35105:4;35081:39;;;;-1:-1:-1;;;;;35081:39:0;;;;;;;;;:15;;;;;;:39;;;;;;;;;;;;;;;:15;:39;;;5:2:-1;;;;30:1;27;20:12;5:2;35081:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;35081:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;35081:39:0;:44;35064:62;35056:152;;;;-1:-1:-1;;;35056:152:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35245:62;;;-1:-1:-1;;;;;35245:62:0;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;35245:62:0;;;;;;;;25:18:-1;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;35219:89:0;;35238:5;;35219:18;:89::i;159053:329::-;159238:136;159262:9;159286;159310:6;159331:12;159358:5;159390:1426;159631:30;:5;6177:8;159631:30;:11;:30;:::i;:::-;159630:31;159584:42;:5;6679:10;159584:42;:11;:42;:::i;:::-;159583:43;:78;159579:1148;;;159678:22;;:::i;:::-;159703:13;:11;:13::i;:::-;159678:38;-1:-1:-1;159738:6:0;159733:401;159754:13;159750:1;:17;159733:401;;;159817:6;159824:1;159817:9;;;;;;;;;;;-1:-1:-1;;;;;159797:30:0;:9;-1:-1:-1;;;;;159797:30:0;;159793:326;;;159852:17;159872:6;159879:1;159872:9;;;;;;;;;;;-1:-1:-1;;;;;159872:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;159872:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;159872:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;159872:17:0;;-1:-1:-1;159912:14:0;159929:6;159936:1;159929:9;;;;;;;;;;;-1:-1:-1;;;;;159929:25:0;;159955:6;159963:4;159983:1;159969:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;159969:16:0;;159929:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;159929:57:0;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;159929:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;159929:57:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;159929:57:0;;-1:-1:-1;160009:61:0;160019:10;160031:9;159929:57;160050:12;160064:5;160009:9;:61::i;:::-;160093:7;;;;;;159793:326;159769:3;;159733:401;;;-1:-1:-1;160155:6:0;160150:566;160171:13;160167:1;:17;160150:566;;;160234:6;160241:1;160234:9;;;;;;;;;;;-1:-1:-1;;;;;160214:30:0;:9;-1:-1:-1;;;;;160214:30:0;;160210:491;;;160269:17;160289:6;160296:1;160289:9;;;;;;;;;;;-1:-1:-1;;;;;160289:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;160289:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;160289:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;160289:17:0;;-1:-1:-1;160329:63:0;160341:9;160289:17;160364:6;160372:12;160386:5;160329:11;:63::i;:::-;160445:35;;;-1:-1:-1;;;160445:35:0;;160474:4;160445:35;;;;;;160417:25;;-1:-1:-1;;;;;160445:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;160445:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;160445:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;160445:35:0;;-1:-1:-1;160503:66:0;160539:6;160546:1;160539:9;;;;;;;;;;;-1:-1:-1;;;;;160503:27:0;;;160551:17;160503:66;:27;:66;:::i;:::-;160592:6;160599:1;160592:9;;;;;;;;;;;-1:-1:-1;;;;;160592:23:0;;160616:17;160649:1;160635:16;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;160635:16:0;;160592:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;160592:60:0;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;160592:60:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;160592:60:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;160675:7:0;;-1:-1:-1;;;;;160675:7:0;160210:491;160186:3;;160150:566;;;;159579:1148;;160746:62;160758:9;160769;160780:6;160788:12;160802:5;160746:11;:62::i;155196:716::-;155241:15;;:::i;:::-;-1:-1:-1;155336:568:0;;;;;;;;155383:42;155336:568;;155447:42;155336:568;;;;155511:42;155336:568;;;;;;;155575:42;155336:568;;;;155639:42;155336:568;;;;155703:42;155336:568;;;;155786:42;155336:568;;;;155850:42;155336:568;;;;155196:716;:::o;152736:330::-;152921:137;152946:9;152970;152994:6;153015:12;153042:5;153074:1465;153280:9;-1:-1:-1;;;;;153267:22:0;:9;-1:-1:-1;;;;;153267:22:0;;153263:61;;;153306:7;;153263:61;153386:31;:5;5080;153386:31;:11;:31;:::i;:::-;153340:77;;:42;:5;6679:10;153340:42;:11;:42;:::i;:::-;:77;;;153336:1114;;;153434:25;;:::i;:::-;153462:10;:8;:10::i;:::-;153434:38;-1:-1:-1;153494:6:0;153489:387;153510:14;153506:1;:18;153489:387;;;153574:7;153582:1;153574:10;;;;;;;;;;;-1:-1:-1;;;;;153554:31:0;:9;-1:-1:-1;;;;;153554:31:0;;153550:311;;;153610:17;153630:7;153638:1;153630:10;;;;;;;;;;;-1:-1:-1;;;;;153630:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;153630:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;153630:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;153630:18:0;;-1:-1:-1;153671:7:0;153679:1;153671:10;;;;;;;;;;;-1:-1:-1;;;;;153671:19:0;;153691:6;153671:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;153671:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;153671:27:0;;;;153721:91;153732:10;153744:9;153755:10;-1:-1:-1;;;;;153755:20:0;;153784:4;153755:35;;;;;;;;;;;;;-1:-1:-1;;;;;153755:35:0;-1:-1:-1;;;;;153755:35:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;153755:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;153755:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;153755:35:0;153792:12;153806:5;153721:10;:91::i;:::-;153835:7;;;;;153550:311;153526:3;;153489:387;;;-1:-1:-1;153897:6:0;153892:547;153913:14;153909:1;:18;153892:547;;;153977:7;153985:1;153977:10;;;;;;;;;;;-1:-1:-1;;;;;153957:31:0;:9;-1:-1:-1;;;;;153957:31:0;;153953:471;;;154013:17;154033:7;154041:1;154033:10;;;;;;;;;;;-1:-1:-1;;;;;154033:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;154033:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154033:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;154033:18:0;;-1:-1:-1;154074:63:0;154086:9;154033:18;154109:6;154117:12;154131:5;154074:11;:63::i;:::-;154190:35;;;-1:-1:-1;;;154190:35:0;;154219:4;154190:35;;;;;;154162:25;;-1:-1:-1;;;;;154190:20:0;;;;;:35;;;;;;;;;;;;;;;:20;:35;;;5:2:-1;;;;30:1;27;20:12;5:2;154190:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154190:35:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;154190:35:0;;-1:-1:-1;154248:67:0;154284:7;154292:1;154284:10;;;;;;154248:67;154338:7;154346:1;154338:10;;;;;;;;;;;-1:-1:-1;;;;;154338:18:0;;154357:17;154338:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;154338:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;154338:37:0;;;;154398:7;;;;;;153953:471;153929:3;;153892:547;;;;153336:1114;;154469:62;154481:9;154492;154503:6;154511:12;154525:5;154469:11;:62::i;148301:943::-;148343:17;;:::i;:::-;-1:-1:-1;148373:863:0;;;;;;;;148402:42;148373:863;;148467:42;148373:863;;;;148532:42;148373:863;;;;;;;148597:42;148373:863;;;;148662:42;148373:863;;;;148727:42;148373:863;;;;148792:42;148373:863;;;;148857:42;148373:863;;;;148922:42;148373:863;;;;148987:42;148373:863;;;;149052:42;148373:863;;;;149117:42;148373:863;;;;149182:42;148373:863;;;;148301:943;:::o;130744:333::-;130929:140;130957:9;130981;131005:6;131026:12;131053:5;131085:1867;131294:9;-1:-1:-1;;;;;131281:22:0;:9;-1:-1:-1;;;;;131281:22:0;;131277:61;;;131320:7;;131277:61;131400:34;:5;4610:4;131400:34;:11;:34;:::i;:::-;131354:80;;:42;:5;6679:10;131354:42;:11;:42;:::i;:::-;:80;;;131350:1437;;;131471:66;;;-1:-1:-1;;;131471:66:0;;-1:-1:-1;;;;;131471:66:0;;;;;;;;131451:17;;52920:42;;131471:30;;:66;;;;;;;;;;;;;;;52920:42;131471:66;;;5:2:-1;;;;30:1;27;20:12;5:2;131471:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;131471:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;131471:66:0;;-1:-1:-1;;;;;;131556:23:0;;;131552:430;;131623:9;-1:-1:-1;;;;;131600:41:0;;131642:6;131600:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;131600:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;131600:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;131668:24:0;;-1:-1:-1;131695:44:0;-1:-1:-1;;;;;131695:29:0;;131733:4;131695:44;:29;:44;:::i;:::-;131668:71;;131767:199;131803:10;131836:9;131868:16;131907:12;131942:5;131767:13;:199::i;:::-;131760:206;;;;131552:430;132011:66;;;-1:-1:-1;;;132011:66:0;;-1:-1:-1;;;;;132011:66:0;;;;;;;;52920:42;;132011:30;;:66;;;;;;;;;;;;;;52920:42;132011:66;;;5:2:-1;;;;30:1;27;20:12;5:2;132011:66:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;132011:66:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;132011:66:0;;-1:-1:-1;;;;;;132096:23:0;;;132092:684;;132140:187;132174:9;132206:10;132239:6;132268:12;132303:5;132140:11;:187::i;:::-;132348:24;132375:44;-1:-1:-1;;;;;132375:29:0;;132413:4;132375:44;:29;:44;:::i;:::-;132348:71;;132444:18;:10;-1:-1:-1;;;;;132444:16:0;;:18::i;:::-;132440:296;;;51864:42;-1:-1:-1;;;;;132487:9:0;;132503:16;132487:35;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;132487:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;132487:35:0;;;;;132440:296;;132092:684;131350:1437;;132806:138;132832:9;132856;132880:6;132901:12;132928:5;137979:332;138164:139;138191:9;138215;138239:6;138260:12;138287:5;138527:9;-1:-1:-1;;;;;138514:22:0;:9;-1:-1:-1;;;;;138514:22:0;;138510:61;;;138553:7;;138510:61;138633:33;:5;4670:4;138633:33;:11;:33;:::i;:::-;138587:79;;:42;:5;6679:10;138587:42;:11;:42;:::i;:::-;:79;;;138583:1618;;;138683:17;138703:26;138719:9;138703:15;:26::i;:::-;138683:46;-1:-1:-1;;;;;;138748:24:0;;;;138744:626;;138797:18;:10;-1:-1:-1;;;;;138797:16:0;;:18::i;:::-;138793:245;;;138840:68;;;-1:-1:-1;;;138840:68:0;;138894:4;138840:68;;;;;;;;;;;;-1:-1:-1;;;;;138840:45:0;;;;;:68;;;;;;;;;;;;;;-1:-1:-1;138840:45:0;:68;;;5:2:-1;;;;30:1;27;20:12;5:2;138840:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;138840:68:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;138793:245:0;;-1:-1:-1;138793:245:0;;138957:61;;;-1:-1:-1;;;138957:61:0;;139004:4;138957:61;;;;;;;;;;;;-1:-1:-1;;;;;138957:38:0;;;;;:61;;;;;;;;;;;;;;-1:-1:-1;138957:38:0;:61;;;5:2:-1;;;;30:1;27;20:12;5:2;138957:61:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;138957:61:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;138793:245:0;139058:24;139085:44;-1:-1:-1;;;;;139085:29:0;;139123:4;139085:44;:29;:44;:::i;:::-;139058:71;;139157:197;139191:10;139224:9;139256:16;139295:12;139330:5;139157:11;:197::i;138744:626::-;139399:26;139415:9;139399:15;:26::i;:::-;139386:39;-1:-1:-1;;;;;;139444:24:0;;;;139440:750;;139489:187;139523:9;139555:10;139588:6;139617:12;139652:5;139489:11;:187::i;:::-;139697:24;139724:44;-1:-1:-1;;;;;139724:29:0;;139762:4;139724:44;:29;:44;:::i;:::-;139697:71;;139793:18;:10;-1:-1:-1;;;;;139793:16:0;;:18::i;:::-;139789:361;;;139836:86;;;-1:-1:-1;;;139836:86:0;;139916:4;139836:86;;;;;;-1:-1:-1;;;;;139836:47:0;;;;;139890:16;;139836:86;;;;;;;;;;;;;;;139890:16;139836:47;:86;;;5:2:-1;;;;30:1;27;20:12;5:2;139836:86:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;139836:86:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;139789:361:0;;-1:-1:-1;139789:361:0;;139971:65;-1:-1:-1;;;;;139971:27:0;;140007:9;140019:16;139971:65;:27;:65;:::i;:::-;140059:71;;;-1:-1:-1;;;140059:71:0;;140106:4;140059:71;;;;;;;;;;;;-1:-1:-1;;;;;140059:38:0;;;;;:71;;;;;;;;;;;;;;-1:-1:-1;140059:38:0;:71;;;5:2:-1;;;;30:1;27;20:12;139440:750:0;138583:1618;;140220:138;140246:9;140270;140294:6;140315:12;140342:5;140220:11;:138::i;133780:1173::-;133841:6;133864:13;:5;-1:-1:-1;;;;;133864:11:0;;:13::i;:::-;133860:63;;;-1:-1:-1;;;133894:17:0;;133860:63;134007:57;;;22:32:-1;6:49;;134007:57:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;133971:94:0;;;;133936:12;;133950:17;;-1:-1:-1;;;;;133971:25:0;;;134001:4;;134007:57;;133971:94;;;;25:18:-1;133971:94:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;133971:94:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;133935:130:0;;;;134081:7;134076:58;;-1:-1:-1;;134105:17:0;;;;;;134076:58;134146:13;;134178:414;134203:4;:11;134195:1;134199;134195:5;:19;134178:414;;;134240:4;134245:1;134249;134245:5;134240:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134240:11:0;-1:-1:-1;;;134240:18:0;:57;;;;;134279:4;134284:1;134288;134284:5;134279:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134279:11:0;-1:-1:-1;;;134279:18:0;134240:57;:96;;;;;134318:4;134323:1;134327;134323:5;134318:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134318:11:0;-1:-1:-1;;;134318:18:0;134240:96;:135;;;;;134357:4;134362:1;134366;134362:5;134357:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134357:11:0;-1:-1:-1;;;134357:18:0;134240:135;:174;;;;;134396:4;134401:1;134405;134401:5;134396:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134396:11:0;-1:-1:-1;;;134396:18:0;134240:174;:213;;;;;134435:4;134440:1;134444;134440:5;134435:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134435:11:0;-1:-1:-1;;;134435:18:0;134240:213;:252;;;;;134474:4;134479:1;134483;134479:5;134474:11;;;;;;;;;;;;;-1:-1:-1;;;;;;134474:11:0;-1:-1:-1;;;134474:18:0;134240:252;134236:345;;;134537:4;134526:15;;134560:5;;134236:345;134216:3;;134178:414;;;;134607:8;134602:59;;-1:-1:-1;;134632:17:0;;;;;;;134602:59;134727:103;;;22:32:-1;6:49;;134727:103:0;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;134691:140:0;;;;-1:-1:-1;;;;;134691:25:0;;;134721:4;;134727:103;134691:140;;;25:18:-1;134691:140:0;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;134691:140:0;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;-1:-1;134673:158:0;;-1:-1:-1;134673:158:0;-1:-1:-1;134673:158:0;134842:58;;-1:-1:-1;;134871:17:0;;;;;;;134842:58;134930:4;134919:26;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;134919:26:0;;133780:1173;-1:-1:-1;;;;;133780:1173:0:o;163601:329::-;163786:136;163810:9;163834;163858:6;163879:12;163906:5;163938:1731;164143:9;-1:-1:-1;;;;;164130:22:0;:9;-1:-1:-1;;;;;164130:22:0;;164126:61;;;164169:7;;164126:61;164249:30;:5;4784:4;164249:30;:11;:30;:::i;:::-;164203:76;;:42;:5;6679:10;164203:42;:11;:42;:::i;:::-;:76;;;164199:1305;;;164316:58;;;-1:-1:-1;;;164316:58:0;;-1:-1:-1;;;;;164316:58:0;;;;;;;;164296:17;;53031:42;;164316:26;;:58;;;;;;;;;;;;;;;53031:42;164316:58;;;5:2:-1;;;;30:1;27;20:12;5:2;164316:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;164316:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;164316:58:0;;-1:-1:-1;;;;;;164393:23:0;;;164389:322;;164456:9;-1:-1:-1;;;;;164437:37:0;;164475:6;164437:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;164437:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;164437:45:0;;;;164510:185;164542:10;164575:9;164607:6;164636:12;164671:5;164510:9;:185::i;:::-;164503:192;;;164389:322;164740:58;;;-1:-1:-1;;;164740:58:0;;-1:-1:-1;;;;;164740:58:0;;;;;;;;53031:42;;164740:26;;:58;;;;;;;;;;;;;;53031:42;164740:58;;;5:2:-1;;;;30:1;27;20:12;5:2;164740:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;164740:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;164740:58:0;;-1:-1:-1;;;;;;164817:23:0;;;164813:680;;164861:187;164895:9;164927:10;164960:6;164989:12;165024:5;164861:11;:187::i;:::-;165069:24;165096:44;-1:-1:-1;;;;;165096:29:0;;165134:4;165096:44;:29;:44;:::i;:::-;165069:71;;165161:58;51660:42;-1:-1:-1;;;;;165189:9:0;;:11;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;165189:11:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165189:11:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165189:11:0;-1:-1:-1;;;;;165161:27:0;;;165202:16;165161:58;:27;:58;:::i;:::-;51660:42;165238:12;165257:18;-1:-1:-1;;;;;165257:16:0;;;:18::i;:::-;:41;;165297:1;165257:41;;;165278:16;165257:41;165322:18;:10;-1:-1:-1;;;;;165322:16:0;;:18::i;:::-;:45;;165357:10;165322:45;;;48103:42;165322:45;165238:214;;;-1:-1:-1;;;;;;165238:214:0;;;;;;;-1:-1:-1;;;;;165238:214:0;;;;;;;;;;;;;165429:4;165238:214;;;;;;;;;;-1:-1:-1;;165238:214:0;;;;;;;;;;;;5:2:-1;;;;30:1;27;20:12;5:2;165238:214:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165238:214:0;;;;;165471:7;;;;164813:680;164199:1305;;165523:138;165549:9;165573;165597:6;165618:12;165645:5;146145:1707;146347:9;-1:-1:-1;;;;;146334:22:0;:9;-1:-1:-1;;;;;146334:22:0;;146330:61;;;146373:7;;146330:61;146453:30;:5;5021;146453:30;:11;:30;:::i;:::-;146407:76;;:42;:5;6679:10;146407:42;:11;:42;:::i;:::-;:76;;;146403:1360;;;-1:-1:-1;;;;;146504:25:0;;144096:42;146504:25;146500:913;;;144096:42;-1:-1:-1;;;;;146550:9:0;;146560:6;146550:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;146550:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;146609:28:0;;;-1:-1:-1;;;146609:28:0;;146631:4;146609:28;;;;;;146588:18;;-1:-1:-1;144184:42:0;;-1:-1:-1;146609:13:0;;:28;;;;;;;;;;;;;;;144184:42;146609:28;;;5:2:-1;;;;30:1;27;20:12;5:2;146609:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;146609:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;146609:28:0;;-1:-1:-1;146660:14:0;;146656:534;;146701:32;146737:203;144184:42;146811:9;146847:10;146884:1;146912:5;146737:17;:203::i;:::-;146699:241;;;146965:205;144184:42;147027:9;147063:10;147100:15;147142:5;146965;:205::i;:::-;146656:534;;147217:180;-1:-1:-1;;;;;;;;;;;147277:9:0;147309:6;147338:12;147373:5;147217:11;:180::i;146500:913::-;-1:-1:-1;;;;;147433:25:0;;144096:42;147433:25;147429:323;;;147479:56;147491:9;-1:-1:-1;;;;;;;;;;;147507:6:0;147515:12;147529:5;147479:11;:56::i;:::-;147577:28;;;-1:-1:-1;;;147577:28:0;;147599:4;147577:28;;;;;;147556:18;;-1:-1:-1;;;;;;;;;;;48490:42:0;147577:13;;:28;;;;;;;;;;;;;;;48490:42;147577:28;;;5:2:-1;;;;30:1;27;20:12;5:2;147577:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;147577:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;147577:28:0;;-1:-1:-1;147624:47:0;-1:-1:-1;;;;;;;;;;;144096:42:0;147577:28;147624:47;:20;:47;:::i;:::-;144096:42;-1:-1:-1;;;;;147690:9:0;;147700:10;147690:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;147429:323:0;147782:62;147794:9;147805;147816:6;147824:12;147838:5;142426:1337;142628:9;-1:-1:-1;;;;;142615:22:0;:9;-1:-1:-1;;;;;142615:22:0;;142611:61;;;142654:7;;142611:61;142734:30;:5;4727:4;142734:30;:11;:30;:::i;:::-;142688:76;;:42;:5;6679:10;142688:42;:11;:42;:::i;:::-;:76;;;142684:914;;;-1:-1:-1;;;;;142785:25:0;;48402:42;142785:25;142781:328;;;142831:32;;;-1:-1:-1;;;142831:32:0;;142849:4;142831:32;;;;;;;;;;;;48402:42;;142831:9;;:32;;;;;-1:-1:-1;;142831:32:0;;;;;;;-1:-1:-1;48402:42:0;142831:32;;;5:2:-1;;;;30:1;27;20:12;5:2;142831:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;142983:28:0;;;-1:-1:-1;;;142983:28:0;;143005:4;142983:28;;;;;;142891:202;;-1:-1:-1;;;;;;;;;;;;48490:42:0;-1:-1:-1;142951:9:0;;48490:42;;142983:13;;:28;;;;;;;;;;;;;;;48490:42;142983:28;;;5:2:-1;;;;30:1;27;20:12;5:2;142983:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;142983:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;142983:28:0;143034:12;143069:5;142891:11;:202::i;142781:328::-;-1:-1:-1;;;;;143129:25:0;;48402:42;143129:25;143125:462;;;143175:180;143209:9;-1:-1:-1;;;;;;;;;;;143267:6:0;143296:12;143331:5;143175:11;:180::i;:::-;143397:28;;;-1:-1:-1;;;143397:28:0;;143419:4;143397:28;;;;;;143376:18;;-1:-1:-1;;;;;;;;;;;48490:42:0;143397:13;;:28;;;;;;;;;;;;;;;48490:42;143397:28;;;5:2:-1;;;;30:1;27;20:12;5:2;143397:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;143397:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;143397:28:0;;-1:-1:-1;143444:47:0;-1:-1:-1;;;;;;;;;;;48402:42:0;143397:28;143444:47;:20;:47;:::i;:::-;143510:36;;;-1:-1:-1;;;143510:36:0;;143528:4;143510:36;;;;;;;;;;;;48402:42;;143510:9;;:36;;;;;-1:-1:-1;;143510:36:0;;;;;;;-1:-1:-1;48402:42:0;143510:36;;;5:2:-1;;;;30:1;27;20:12;143125:462:0;143617:138;143643:9;143667;143691:6;143712:12;143739:5;173224:2443;173426:9;-1:-1:-1;;;;;173413:22:0;:9;-1:-1:-1;;;;;173413:22:0;;173409:61;;;173452:7;;173409:61;173532:38;:5;7659:13;173532:38;:11;:38;:::i;:::-;173486:84;;:42;:5;6679:10;173486:42;:11;:42;:::i;:::-;:84;;;173482:2020;;;-1:-1:-1;;;;;173591:25:0;;52304:42;173591:25;173587:935;;;-1:-1:-1;;;;;173641:17:0;;48579:42;173641:17;;:37;;-1:-1:-1;;;;;;173662:16:0;;-1:-1:-1;;;;;;;;;;;173662:16:0;173641:37;:58;;;-1:-1:-1;;;;;;173682:17:0;;48668:42;173682:17;173641:58;:79;;;-1:-1:-1;;;;;;173703:17:0;;48757:42;173703:17;173641:79;173637:845;;;173767:59;;;-1:-1:-1;;;173767:59:0;;-1:-1:-1;;;;;173767:59:0;;;;;;;;;;;;;;;;;;;;;173749:14;;52440:42;;173767:29;;:59;;;;;173749:14;;173767:59;;;;;;;;52440:42;173767:59;;;5:2:-1;;;;30:1;27;20:12;5:2;173767:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;173767:59:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;173767:59:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;173767:59:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;173767:59:0;;420:4:-1;411:14;;;;173767:59:0;;;;;411:14:-1;173767:59:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;173767:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;173767:59:0;;;;;;;;;-1:-1:-1;;;173849:103:0;;-1:-1:-1;;;;;173849:103:0;;;;;;;;;;;;;;173767:59;;-1:-1:-1;52304:42:0;;-1:-1:-1;173849:11:0;;-1:-1:-1;173849:103:0;;;;;-1:-1:-1;173767:59:0;;-1:-1:-1;173849:103:0;;;;;;;-1:-1:-1;52304:42:0;173849:103;;;5:2:-1;;;;30:1;27;20:12;5:2;173849:103:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;173849:103:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;173637:845:0;;-1:-1:-1;;173637:845:0;;174040:53;;;-1:-1:-1;;;174040:53:0;;-1:-1:-1;;;;;174040:53:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;174040:53:0;;;;;;174022:14;;52440:42;;174040:29;;:53;;;;;174022:14;;174040:53;;;;;;;;52440:42;174040:53;;;5:2:-1;;;;30:1;27;20:12;5:2;174040:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;174040:53:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;174040:53:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;13:2;5:11;;2:2;;;29:1;26;19:12;2:2;174040:53:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;11:20;;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;-1:-1;;;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;174040:53:0;;420:4:-1;411:14;;;;174040:53:0;;;;;411:14:-1;174040:53:0;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;174040:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;174040:53:0;;;;;;;;;-1:-1:-1;;;174116:97:0;;-1:-1:-1;;;;;;;;;;;174116:97:0;;;;;;;;;;;;174040:53;;-1:-1:-1;52304:42:0;;-1:-1:-1;174116:11:0;;-1:-1:-1;174116:97:0;;;;;-1:-1:-1;174040:53:0;;-1:-1:-1;174116:97:0;;;;;;;-1:-1:-1;52304:42:0;174116:97;;;5:2:-1;;;;30:1;27;20:12;5:2;174116:97:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;174116:97:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;174340:28:0;;;-1:-1:-1;;;174340:28:0;;174362:4;174340:28;;;;;;174236:226;;-1:-1:-1;;;;;;;;;;;48490:42:0;174304:9;;48490:42;;174340:13;;:28;;;;;174116:97;;174340:28;;;;;;;;48490:42;174340:28;;;5:2:-1;;;;30:1;27;20:12;5:2;174340:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;174340:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;174340:28:0;174395:12;174434:5;174236:11;:226::i;173587:935::-;-1:-1:-1;;;;;174542:25:0;;52304:42;174542:25;174538:953;;;-1:-1:-1;;;;;174592:17:0;;48579:42;174592:17;;:37;;-1:-1:-1;;;;;;174613:16:0;;-1:-1:-1;;;;;;;;;;;174613:16:0;174592:37;:58;;;-1:-1:-1;;;;;;174633:17:0;;48668:42;174633:17;174592:58;:79;;;-1:-1:-1;;;;;;174654:17:0;;48757:42;174654:17;174592:79;174588:863;;;174696:49;-1:-1:-1;;;;;174696:26:0;;52304:42;174738:6;174696:49;:26;:49;:::i;:::-;174768:177;;;-1:-1:-1;;;174768:177:0;;-1:-1:-1;;;;;174768:177:0;;;;;;;;;;;;;;;;;;;174917:4;174768:177;;;;;;52304:42;;174768:9;;:177;;;;;;;;;;;;;;-1:-1:-1;52304:42:0;174768:177;;;5:2:-1;;;;30:1;27;20:12;5:2;174768:177:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;174768:177:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;174588:863:0;;-1:-1:-1;174588:863:0;;175011:204;175049:9;-1:-1:-1;;;;;;;;;;;175115:6:0;175148:12;175187:5;175011:11;:204::i;:::-;175340:28;;;-1:-1:-1;;;175340:28:0;;175362:4;175340:28;;;;;;52304:42;;175238:9;;-1:-1:-1;;;;;;;;;;;48490:42:0;175304:9;;48490:42;;175340:13;;:28;;;;;;;;;;;;;;48490:42;175340:28;;;5:2:-1;;;;30:1;27;20:12;5:2;175340:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;175340:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;175340:28:0;175238:193;;;-1:-1:-1;;;;;;175238:193:0;;;;;;;-1:-1:-1;;;;;175238:193:0;;;;;;;;;;;;;;;;;;;175403:4;175238:193;;;;;;;;;;;175340:28;;175238:193;;;;;;;-1:-1:-1;175238:193:0;;;;5:2:-1;;;;30:1;27;20:12;5:2;175238:193:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;175238:193:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;174538:953:0;175521:138;175547:9;175571;175595:6;175616:12;175643:5;102765:437;103001:9;-1:-1:-1;;;;;102988:22:0;:9;-1:-1:-1;;;;;102988:22:0;;102984:61;;;103027:7;;102984:61;103057:137;103082:9;103106;103130:6;103151:12;103178:5;190790:8;;190755:53;;-1:-1:-1;;;;;190755:26:0;;;;190790:8;190801:6;190755:53;:26;:53;:::i;:::-;190819:8;;-1:-1:-1;;;;;190819:8:0;;;;:13;;190839:17;;:15;;;:17::i;:::-;:30;;190868:1;190839:30;;;190859:6;190839:30;190885:9;190909;190933:6;190954:1;190970:12;190997:5;190819:194;;;;;;;;;;;;;-1:-1:-1;;;;;190819:194:0;-1:-1:-1;;;;;190819:194:0;;;;;;-1:-1:-1;;;;;190819:194:0;-1:-1:-1;;;;;190819:194:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;190819:194:0;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;190819:194:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;190819:194:0;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;;190565:456:0:o;185114:5910::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;185114:5910:0;;;-1:-1:-1;;185114:5910:0:o;:::-;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;-1:-1;185114:5910:0;;;-1:-1:-1;;185114:5910:0:o
Swarm Source
bzzr://82422d78f831c964d51b32a4a4d437609f95144f7415ad16456ffa44c296a856
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.