Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 4 from a total of 4 transactions
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
13306093 | 1187 days ago | 2 wei | ||||
13306093 | 1187 days ago | 2 wei | ||||
13306093 | 1187 days ago | 2.2 ETH | ||||
13306093 | 1187 days ago | 2.2 ETH | ||||
13305959 | 1187 days ago | 0 ETH | ||||
13305959 | 1187 days ago | 0 ETH | ||||
13305959 | 1187 days ago | 1,290 ETH | ||||
13305959 | 1187 days ago | 1,290 ETH | ||||
13305948 | 1187 days ago | 1,290 ETH | ||||
13305948 | 1187 days ago | 1,290 ETH | ||||
13305917 | 1187 days ago | 1,036.60735104 ETH | ||||
13305917 | 1187 days ago | 1,036.60735104 ETH | ||||
13305917 | 1187 days ago | 1,042.78106025 ETH | ||||
13305917 | 1187 days ago | 1,042.78106025 ETH | ||||
13300959 | 1188 days ago | 1.66779928 ETH | ||||
13300959 | 1188 days ago | 1.66779928 ETH | ||||
13299483 | 1188 days ago | 1,290 ETH | ||||
13299483 | 1188 days ago | 1,290 ETH | ||||
13299466 | 1188 days ago | 1,290 ETH | ||||
13299466 | 1188 days ago | 1,290 ETH | ||||
13299429 | 1188 days ago | 1,357.86340618 ETH | ||||
13299429 | 1188 days ago | 1,357.86340618 ETH | ||||
13299429 | 1188 days ago | 1,358.01263782 ETH | ||||
13299429 | 1188 days ago | 1,358.01263782 ETH | ||||
13299395 | 1188 days ago | 0.33029261 ETH |
Loading...
Loading
Contract Name:
SushiswapSpellV1
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-04-28 */ // SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // Part: IBank interface IBank { /// The governor adds a new bank gets added to the system. event AddBank(address token, address cToken); /// The governor sets the address of the oracle smart contract. event SetOracle(address oracle); /// The governor sets the basis point fee of the bank. event SetFeeBps(uint feeBps); /// The governor withdraw tokens from the reserve of a bank. event WithdrawReserve(address user, address token, uint amount); /// Someone borrows tokens from a bank via a spell caller. event Borrow(uint positionId, address caller, address token, uint amount, uint share); /// Someone repays tokens to a bank via a spell caller. event Repay(uint positionId, address caller, address token, uint amount, uint share); /// Someone puts tokens as collateral via a spell caller. event PutCollateral(uint positionId, address caller, address token, uint id, uint amount); /// Someone takes tokens from collateral via a spell caller. event TakeCollateral(uint positionId, address caller, address token, uint id, uint amount); /// Someone calls liquidatation on a position, paying debt and taking collateral tokens. event Liquidate( uint positionId, address liquidator, address debtToken, uint amount, uint share, uint bounty ); /// @dev Return the current position while under execution. function POSITION_ID() external view returns (uint); /// @dev Return the current target while under execution. function SPELL() external view returns (address); /// @dev Return the current executor (the owner of the current position). function EXECUTOR() external view returns (address); /// @dev Return bank information for the given token. function getBankInfo(address token) external view returns ( bool isListed, address cToken, uint reserve, uint totalDebt, uint totalShare ); /// @dev Return position information for the given position id. function getPositionInfo(uint positionId) external view returns ( address owner, address collToken, uint collId, uint collateralSize ); /// @dev Return the borrow balance for given positon and token without trigger interest accrual. function borrowBalanceStored(uint positionId, address token) external view returns (uint); /// @dev Trigger interest accrual and return the current borrow balance. function borrowBalanceCurrent(uint positionId, address token) external returns (uint); /// @dev Borrow tokens from the bank. function borrow(address token, uint amount) external; /// @dev Repays tokens to the bank. function repay(address token, uint amountCall) external; /// @dev Transmit user assets to the spell. function transmit(address token, uint amount) external; /// @dev Put more collateral for users. function putCollateral( address collToken, uint collId, uint amountCall ) external; /// @dev Take some collateral back. function takeCollateral( address collToken, uint collId, uint amount ) external; /// @dev Liquidate a position. function liquidate( uint positionId, address debtToken, uint amountCall ) external; function getBorrowETHValue(uint positionId) external view returns (uint); function accrue(address token) external; function nextPositionId() external view returns (uint); /// @dev Return current position information. function getCurrentPositionInfo() external view returns ( address owner, address collToken, uint collId, uint collateralSize ); function support(address token) external view returns (bool); } // Part: IERC20Wrapper interface IERC20Wrapper { /// @dev Return the underlying ERC-20 for the given ERC-1155 token id. function getUnderlyingToken(uint id) external view returns (address); /// @dev Return the conversion rate from ERC-1155 to ERC-20, multiplied by 2**112. function getUnderlyingRate(uint id) external view returns (uint); } // Part: IMasterChef interface IMasterChef { function sushi() external view returns (address); function poolInfo(uint pid) external view returns ( address lpToken, uint allocPoint, uint lastRewardBlock, uint accSushiPerShare ); function deposit(uint pid, uint amount) external; function withdraw(uint pid, uint amount) external; } // Part: IUniswapV2Factory // https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } // Part: IUniswapV2Pair // https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Pair.sol interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit( address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap( uint amount0Out, uint amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } // Part: IUniswapV2Router01 // https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router01.sol interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns ( uint amountA, uint amountB, uint liquidity ); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns ( uint amountToken, uint amountETH, uint liquidity ); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function swapTokensForExactETH( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactTokensForETH( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapETHForExactTokens( uint amountOut, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function quote( uint amountA, uint reserveA, uint reserveB ) external pure returns (uint amountB); function getAmountOut( uint amountIn, uint reserveIn, uint reserveOut ) external pure returns (uint amountOut); function getAmountIn( uint amountOut, uint reserveIn, uint reserveOut ) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); } // Part: IUniswapV2Router02 interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; } // Part: IWETH interface IWETH { function balanceOf(address user) external returns (uint); function approve(address to, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function deposit() external payable; function withdraw(uint) external; } // Part: OpenZeppelin/[email protected]/Address /** * @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) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @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]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // Part: OpenZeppelin/[email protected]/IERC165 /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // Part: OpenZeppelin/[email protected]/IERC20 /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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); } // Part: OpenZeppelin/[email protected]/SafeMath /** * @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, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @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) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @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) { 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, reverting 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) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting 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) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * 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, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * 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, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } } // Part: HomoraMath library HomoraMath { using SafeMath for uint; function divCeil(uint lhs, uint rhs) internal pure returns (uint) { return lhs.add(rhs).sub(1) / rhs; } function fmul(uint lhs, uint rhs) internal pure returns (uint) { return lhs.mul(rhs) / (2**112); } function fdiv(uint lhs, uint rhs) internal pure returns (uint) { return lhs.mul(2**112) / rhs; } // implementation from https://github.com/Uniswap/uniswap-lib/commit/99f3f28770640ba1bb1ff460ac7c5292fb8291a0 // original implementation: https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687 function sqrt(uint x) internal pure returns (uint) { if (x == 0) return 0; uint xx = x; uint r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint r1 = x / r; return (r < r1 ? r : r1); } } // Part: OpenZeppelin/[email protected]/ERC165 /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // Part: OpenZeppelin/[email protected]/IERC1155 /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external; } // Part: OpenZeppelin/[email protected]/IERC1155Receiver /** * _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** @dev Handles the receipt of a single ERC1155 token type. This function is called at the end of a `safeTransferFrom` after the balance has been updated. To accept the transfer, this must return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61, or its own function selector). @param operator The address which initiated the transfer (i.e. msg.sender) @param from The address which previously owned the token @param id The ID of the token being transferred @param value The amount of tokens being transferred @param data Additional data with no specified format @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns(bytes4); /** @dev Handles the receipt of a multiple ERC1155 token types. This function is called at the end of a `safeBatchTransferFrom` after the balances have been updated. To accept the transfer(s), this must return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81, or its own function selector). @param operator The address which initiated the batch transfer (i.e. msg.sender) @param from The address which previously owned the token @param ids An array containing ids of each token being transferred (order and length must match values array) @param values An array containing amounts of each token being transferred (order and length must match ids array) @param data Additional data with no specified format @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns(bytes4); } // Part: OpenZeppelin/[email protected]/Initializable /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !Address.isContract(address(this)); } } // Part: OpenZeppelin/[email protected]/SafeERC20 /** * @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 IERC20;` 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)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ 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. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "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"); } } } // Part: Governable contract Governable is Initializable { event SetGovernor(address governor); event SetPendingGovernor(address pendingGovernor); event AcceptGovernor(address governor); address public governor; // The current governor. address public pendingGovernor; // The address pending to become the governor once accepted. bytes32[64] _gap; // reserve space for upgrade modifier onlyGov() { require(msg.sender == governor, 'not the governor'); _; } /// @dev Initialize using msg.sender as the first governor. function __Governable__init() internal initializer { governor = msg.sender; pendingGovernor = address(0); emit SetGovernor(msg.sender); } /// @dev Set the pending governor, which will be the governor once accepted. /// @param _pendingGovernor The address to become the pending governor. function setPendingGovernor(address _pendingGovernor) external onlyGov { pendingGovernor = _pendingGovernor; emit SetPendingGovernor(_pendingGovernor); } /// @dev Accept to become the new governor. Must be called by the pending governor. function acceptGovernor() external { require(msg.sender == pendingGovernor, 'not the pending governor'); pendingGovernor = address(0); governor = msg.sender; emit AcceptGovernor(msg.sender); } } // Part: IWERC20 interface IWERC20 is IERC1155, IERC20Wrapper { /// @dev Return the underlying ERC20 balance for the user. function balanceOfERC20(address token, address user) external view returns (uint); /// @dev Mint ERC1155 token for the given ERC20 token. function mint(address token, uint amount) external; /// @dev Burn ERC1155 token to redeem ERC20 token back. function burn(address token, uint amount) external; } // Part: IWMasterChef interface IWMasterChef is IERC1155, IERC20Wrapper { /// @dev Mint ERC1155 token for the given ERC20 token. function mint(uint pid, uint amount) external returns (uint id); /// @dev Burn ERC1155 token to redeem ERC20 token back. function burn(uint id, uint amount) external returns (uint pid); function sushi() external returns (IERC20); function decodeId(uint id) external pure returns (uint, uint); function chef() external view returns (IMasterChef); } // Part: OpenZeppelin/[email protected]/ERC1155Receiver /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { constructor() internal { _registerInterface( ERC1155Receiver(address(0)).onERC1155Received.selector ^ ERC1155Receiver(address(0)).onERC1155BatchReceived.selector ); } } // Part: ERC1155NaiveReceiver contract ERC1155NaiveReceiver is ERC1155Receiver { bytes32[64] __gap; // reserve space for upgrade function onERC1155Received( address, /* operator */ address, /* from */ uint, /* id */ uint, /* value */ bytes calldata /* data */ ) external override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, /* operator */ address, /* from */ uint[] calldata, /* ids */ uint[] calldata, /* values */ bytes calldata /* data */ ) external override returns (bytes4) { return this.onERC1155BatchReceived.selector; } } // Part: BasicSpell abstract contract BasicSpell is ERC1155NaiveReceiver { using SafeERC20 for IERC20; IBank public immutable bank; IWERC20 public immutable werc20; address public immutable weth; mapping(address => mapping(address => bool)) public approved; // Mapping from token to (mapping from spender to approve status) constructor( IBank _bank, address _werc20, address _weth ) public { bank = _bank; werc20 = IWERC20(_werc20); weth = _weth; ensureApprove(_weth, address(_bank)); IWERC20(_werc20).setApprovalForAll(address(_bank), true); } /// @dev Ensure that the spell has approved the given spender to spend all of its tokens. /// @param token The token to approve. /// @param spender The spender to allow spending. /// NOTE: This is safe because spell is never built to hold fund custody. function ensureApprove(address token, address spender) internal { if (!approved[token][spender]) { IERC20(token).safeApprove(spender, uint(-1)); approved[token][spender] = true; } } /// @dev Internal call to convert msg.value ETH to WETH inside the contract. function doTransmitETH() internal { if (msg.value > 0) { IWETH(weth).deposit{value: msg.value}(); } } /// @dev Internal call to transmit tokens from the bank if amount is positive. /// @param token The token to perform the transmit action. /// @param amount The amount to transmit. /// @notice Do not use `amount` input argument to handle the received amount. function doTransmit(address token, uint amount) internal { if (amount > 0) { bank.transmit(token, amount); } } /// @dev Internal call to refund tokens to the current bank executor. /// @param token The token to perform the refund action. function doRefund(address token) internal { uint balance = IERC20(token).balanceOf(address(this)); if (balance > 0) { IERC20(token).safeTransfer(bank.EXECUTOR(), balance); } } /// @dev Internal call to refund all WETH to the current executor as native ETH. function doRefundETH() internal { uint balance = IWETH(weth).balanceOf(address(this)); if (balance > 0) { IWETH(weth).withdraw(balance); (bool success, ) = bank.EXECUTOR().call{value: balance}(new bytes(0)); require(success, 'refund ETH failed'); } } /// @dev Internal call to borrow tokens from the bank on behalf of the current executor. /// @param token The token to borrow from the bank. /// @param amount The amount to borrow. /// @notice Do not use `amount` input argument to handle the received amount. function doBorrow(address token, uint amount) internal { if (amount > 0) { bank.borrow(token, amount); } } /// @dev Internal call to repay tokens to the bank on behalf of the current executor. /// @param token The token to repay to the bank. /// @param amount The amount to repay. function doRepay(address token, uint amount) internal { if (amount > 0) { ensureApprove(token, address(bank)); bank.repay(token, amount); } } /// @dev Internal call to put collateral tokens in the bank. /// @param token The token to put in the bank. /// @param amount The amount to put in the bank. function doPutCollateral(address token, uint amount) internal { if (amount > 0) { ensureApprove(token, address(werc20)); werc20.mint(token, amount); bank.putCollateral(address(werc20), uint(token), amount); } } /// @dev Internal call to take collateral tokens from the bank. /// @param token The token to take back. /// @param amount The amount to take back. function doTakeCollateral(address token, uint amount) internal { if (amount > 0) { if (amount == uint(-1)) { (, , , amount) = bank.getCurrentPositionInfo(); } bank.takeCollateral(address(werc20), uint(token), amount); werc20.burn(token, amount); } } /// @dev Fallback function. Can only receive ETH from WETH contract. receive() external payable { require(msg.sender == weth, 'ETH must come from WETH'); } } // Part: WhitelistSpell contract WhitelistSpell is BasicSpell, Governable { mapping(address => bool) public whitelistedLpTokens; // mapping from lp token to whitelist status constructor( IBank _bank, address _werc20, address _weth ) public BasicSpell(_bank, _werc20, _weth) { __Governable__init(); } /// @dev Set whitelist LP token statuses for spell /// @param lpTokens LP tokens to set whitelist statuses /// @param statuses Whitelist statuses function setWhitelistLPTokens(address[] calldata lpTokens, bool[] calldata statuses) external onlyGov { require(lpTokens.length == statuses.length, 'lpTokens & statuses length mismatched'); for (uint idx = 0; idx < lpTokens.length; idx++) { if (statuses[idx]) { require(bank.support(lpTokens[idx]), 'oracle not support lp token'); } whitelistedLpTokens[lpTokens[idx]] = statuses[idx]; } } } // File: SushiswapSpellV1.sol contract SushiswapSpellV1 is WhitelistSpell { using SafeMath for uint; using HomoraMath for uint; IUniswapV2Factory public immutable factory; // Sushiswap factory IUniswapV2Router02 public immutable router; // Sushiswap router mapping(address => mapping(address => address)) public pairs; // Mapping from tokenA to (mapping from tokenB to LP token) IWMasterChef public immutable wmasterchef; // Wrapped masterChef address public immutable sushi; // Sushi token address constructor( IBank _bank, address _werc20, IUniswapV2Router02 _router, address _wmasterchef ) public WhitelistSpell(_bank, _werc20, _router.WETH()) { router = _router; factory = IUniswapV2Factory(_router.factory()); wmasterchef = IWMasterChef(_wmasterchef); IWMasterChef(_wmasterchef).setApprovalForAll(address(_bank), true); sushi = address(IWMasterChef(_wmasterchef).sushi()); } /// @dev Return the LP token for the token pairs (can be in any order) /// @param tokenA Token A to get LP token /// @param tokenB Token B to get LP token function getAndApprovePair(address tokenA, address tokenB) public returns (address) { address lp = pairs[tokenA][tokenB]; if (lp == address(0)) { lp = factory.getPair(tokenA, tokenB); require(lp != address(0), 'no lp token'); ensureApprove(tokenA, address(router)); ensureApprove(tokenB, address(router)); ensureApprove(lp, address(router)); pairs[tokenA][tokenB] = lp; pairs[tokenB][tokenA] = lp; } return lp; } /// @dev Compute optimal deposit amount /// @param amtA amount of token A desired to deposit /// @param amtB amount of token B desired to deposit /// @param resA amount of token A in reserve /// @param resB amount of token B in reserve function optimalDeposit( uint amtA, uint amtB, uint resA, uint resB ) internal pure returns (uint swapAmt, bool isReversed) { if (amtA.mul(resB) >= amtB.mul(resA)) { swapAmt = _optimalDepositA(amtA, amtB, resA, resB); isReversed = false; } else { swapAmt = _optimalDepositA(amtB, amtA, resB, resA); isReversed = true; } } /// @dev Compute optimal deposit amount helper. /// @param amtA amount of token A desired to deposit /// @param amtB amount of token B desired to deposit /// @param resA amount of token A in reserve /// @param resB amount of token B in reserve /// Formula: https://blog.alphafinance.io/byot/ function _optimalDepositA( uint amtA, uint amtB, uint resA, uint resB ) internal pure returns (uint) { require(amtA.mul(resB) >= amtB.mul(resA), 'Reversed'); uint a = 997; uint b = uint(1997).mul(resA); uint _c = (amtA.mul(resB)).sub(amtB.mul(resA)); uint c = _c.mul(1000).div(amtB.add(resB)).mul(resA); uint d = a.mul(c).mul(4); uint e = HomoraMath.sqrt(b.mul(b).add(d)); uint numerator = e.sub(b); uint denominator = a.mul(2); return numerator.div(denominator); } struct Amounts { uint amtAUser; // Supplied tokenA amount uint amtBUser; // Supplied tokenB amount uint amtLPUser; // Supplied LP token amount uint amtABorrow; // Borrow tokenA amount uint amtBBorrow; // Borrow tokenB amount uint amtLPBorrow; // Borrow LP token amount uint amtAMin; // Desired tokenA amount (slippage control) uint amtBMin; // Desired tokenB amount (slippage control) } /// @dev Add liquidity to Sushiswap pool /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to supply, borrow, and get. function addLiquidityInternal( address tokenA, address tokenB, Amounts calldata amt, address lp ) internal { require(whitelistedLpTokens[lp], 'lp token not whitelisted'); // 1. Get user input amounts doTransmitETH(); doTransmit(tokenA, amt.amtAUser); doTransmit(tokenB, amt.amtBUser); doTransmit(lp, amt.amtLPUser); // 2. Borrow specified amounts doBorrow(tokenA, amt.amtABorrow); doBorrow(tokenB, amt.amtBBorrow); doBorrow(lp, amt.amtLPBorrow); // 3. Calculate optimal swap amount uint swapAmt; bool isReversed; { uint amtA = IERC20(tokenA).balanceOf(address(this)); uint amtB = IERC20(tokenB).balanceOf(address(this)); uint resA; uint resB; if (IUniswapV2Pair(lp).token0() == tokenA) { (resA, resB, ) = IUniswapV2Pair(lp).getReserves(); } else { (resB, resA, ) = IUniswapV2Pair(lp).getReserves(); } (swapAmt, isReversed) = optimalDeposit(amtA, amtB, resA, resB); } // 4. Swap optimal amount if (swapAmt > 0) { address[] memory path = new address[](2); (path[0], path[1]) = isReversed ? (tokenB, tokenA) : (tokenA, tokenB); router.swapExactTokensForTokens(swapAmt, 0, path, address(this), block.timestamp); } // 5. Add liquidity uint balA = IERC20(tokenA).balanceOf(address(this)); uint balB = IERC20(tokenB).balanceOf(address(this)); if (balA > 0 || balB > 0) { router.addLiquidity( tokenA, tokenB, balA, balB, amt.amtAMin, amt.amtBMin, address(this), block.timestamp ); } } /// @dev Add liquidity to Sushiswap pool, with no staking rewards (use WERC20 wrapper) /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to supply, borrow, and get. function addLiquidityWERC20( address tokenA, address tokenB, Amounts calldata amt ) external payable { address lp = getAndApprovePair(tokenA, tokenB); // 1-5. add liquidity addLiquidityInternal(tokenA, tokenB, amt, lp); // 6. Put collateral doPutCollateral(lp, IERC20(lp).balanceOf(address(this))); // 7. Refund leftovers to users doRefundETH(); doRefund(tokenA); doRefund(tokenB); } /// @dev Add liquidity to Sushiswap pool, with staking to masterChef /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to supply, borrow, and get. /// @param pid Pool id function addLiquidityWMasterChef( address tokenA, address tokenB, Amounts calldata amt, uint pid ) external payable { address lp = getAndApprovePair(tokenA, tokenB); (address lpToken, , , ) = wmasterchef.chef().poolInfo(pid); require(lpToken == lp, 'incorrect lp token'); // 1-5. add liquidity addLiquidityInternal(tokenA, tokenB, amt, lp); // 6. Take out collateral (, address collToken, uint collId, uint collSize) = bank.getCurrentPositionInfo(); if (collSize > 0) { (uint decodedPid, ) = wmasterchef.decodeId(collId); require(pid == decodedPid, 'incorrect pid'); require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched'); bank.takeCollateral(address(wmasterchef), collId, collSize); wmasterchef.burn(collId, collSize); } // 7. Put collateral ensureApprove(lp, address(wmasterchef)); uint amount = IERC20(lp).balanceOf(address(this)); uint id = wmasterchef.mint(pid, amount); bank.putCollateral(address(wmasterchef), id, amount); // 8. Refund leftovers to users doRefundETH(); doRefund(tokenA); doRefund(tokenB); // 9. Refund sushi doRefund(sushi); } struct RepayAmounts { uint amtLPTake; // Take out LP token amount (from Homora) uint amtLPWithdraw; // Withdraw LP token amount (back to caller) uint amtARepay; // Repay tokenA amount uint amtBRepay; // Repay tokenB amount uint amtLPRepay; // Repay LP token amount uint amtAMin; // Desired tokenA amount uint amtBMin; // Desired tokenB amount } /// @dev Remove liquidity from Sushiswap pool /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to take out, withdraw, repay, and get. function removeLiquidityInternal( address tokenA, address tokenB, RepayAmounts calldata amt, address lp ) internal { require(whitelistedLpTokens[lp], 'lp token not whitelisted'); uint positionId = bank.POSITION_ID(); uint amtARepay = amt.amtARepay; uint amtBRepay = amt.amtBRepay; uint amtLPRepay = amt.amtLPRepay; // 2. Compute repay amount if MAX_INT is supplied (max debt) if (amtARepay == uint(-1)) { amtARepay = bank.borrowBalanceCurrent(positionId, tokenA); } if (amtBRepay == uint(-1)) { amtBRepay = bank.borrowBalanceCurrent(positionId, tokenB); } if (amtLPRepay == uint(-1)) { amtLPRepay = bank.borrowBalanceCurrent(positionId, lp); } // 3. Compute amount to actually remove uint amtLPToRemove = IERC20(lp).balanceOf(address(this)).sub(amt.amtLPWithdraw); // 4. Remove liquidity uint amtA; uint amtB; if (amtLPToRemove > 0) { (amtA, amtB) = router.removeLiquidity( tokenA, tokenB, amtLPToRemove, 0, 0, address(this), block.timestamp ); } // 5. MinimizeTrading uint amtADesired = amtARepay.add(amt.amtAMin); uint amtBDesired = amtBRepay.add(amt.amtBMin); if (amtA < amtADesired && amtB > amtBDesired) { address[] memory path = new address[](2); (path[0], path[1]) = (tokenB, tokenA); router.swapTokensForExactTokens( amtADesired.sub(amtA), amtB.sub(amtBDesired), path, address(this), block.timestamp ); } else if (amtA > amtADesired && amtB < amtBDesired) { address[] memory path = new address[](2); (path[0], path[1]) = (tokenA, tokenB); router.swapTokensForExactTokens( amtBDesired.sub(amtB), amtA.sub(amtADesired), path, address(this), block.timestamp ); } // 6. Repay doRepay(tokenA, amtARepay); doRepay(tokenB, amtBRepay); doRepay(lp, amtLPRepay); // 7. Slippage control require(IERC20(tokenA).balanceOf(address(this)) >= amt.amtAMin); require(IERC20(tokenB).balanceOf(address(this)) >= amt.amtBMin); require(IERC20(lp).balanceOf(address(this)) >= amt.amtLPWithdraw); // 8. Refund leftover doRefundETH(); doRefund(tokenA); doRefund(tokenB); doRefund(lp); } /// @dev Remove liquidity from Sushiswap pool, with no staking rewards (use WERC20 wrapper) /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to take out, withdraw, repay, and get. function removeLiquidityWERC20( address tokenA, address tokenB, RepayAmounts calldata amt ) external { address lp = getAndApprovePair(tokenA, tokenB); // 1. Take out collateral doTakeCollateral(lp, amt.amtLPTake); // 2-8. remove liquidity removeLiquidityInternal(tokenA, tokenB, amt, lp); } /// @dev Remove liquidity from Sushiswap pool, from masterChef staking /// @param tokenA Token A for the pair /// @param tokenB Token B for the pair /// @param amt Amounts of tokens to take out, withdraw, repay, and get. function removeLiquidityWMasterChef( address tokenA, address tokenB, RepayAmounts calldata amt ) external { address lp = getAndApprovePair(tokenA, tokenB); (, address collToken, uint collId, ) = bank.getCurrentPositionInfo(); require(IWMasterChef(collToken).getUnderlyingToken(collId) == lp, 'incorrect underlying'); require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched'); // 1. Take out collateral bank.takeCollateral(address(wmasterchef), collId, amt.amtLPTake); wmasterchef.burn(collId, amt.amtLPTake); // 2-8. remove liquidity removeLiquidityInternal(tokenA, tokenB, amt, lp); // 9. Refund sushi doRefund(sushi); } /// @dev Harvest SUSHI reward tokens to in-exec position's owner function harvestWMasterChef() external { (, address collToken, uint collId, ) = bank.getCurrentPositionInfo(); (uint pid, ) = wmasterchef.decodeId(collId); address lp = wmasterchef.getUnderlyingToken(collId); require(whitelistedLpTokens[lp], 'lp token not whitelisted'); require(collToken == address(wmasterchef), 'collateral token & wmasterchef mismatched'); // 1. Take out collateral bank.takeCollateral(address(wmasterchef), collId, uint(-1)); wmasterchef.burn(collId, uint(-1)); // 2. put collateral uint amount = IERC20(lp).balanceOf(address(this)); ensureApprove(lp, address(wmasterchef)); uint id = wmasterchef.mint(pid, amount); bank.putCollateral(address(wmasterchef), id, amount); // 3. Refund sushi doRefund(sushi); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IBank","name":"_bank","type":"address"},{"internalType":"address","name":"_werc20","type":"address"},{"internalType":"contract IUniswapV2Router02","name":"_router","type":"address"},{"internalType":"address","name":"_wmasterchef","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"governor","type":"address"}],"name":"AcceptGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"governor","type":"address"}],"name":"SetGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingGovernor","type":"address"}],"name":"SetPendingGovernor","type":"event"},{"inputs":[],"name":"acceptGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtAUser","type":"uint256"},{"internalType":"uint256","name":"amtBUser","type":"uint256"},{"internalType":"uint256","name":"amtLPUser","type":"uint256"},{"internalType":"uint256","name":"amtABorrow","type":"uint256"},{"internalType":"uint256","name":"amtBBorrow","type":"uint256"},{"internalType":"uint256","name":"amtLPBorrow","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.Amounts","name":"amt","type":"tuple"}],"name":"addLiquidityWERC20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtAUser","type":"uint256"},{"internalType":"uint256","name":"amtBUser","type":"uint256"},{"internalType":"uint256","name":"amtLPUser","type":"uint256"},{"internalType":"uint256","name":"amtABorrow","type":"uint256"},{"internalType":"uint256","name":"amtBBorrow","type":"uint256"},{"internalType":"uint256","name":"amtLPBorrow","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.Amounts","name":"amt","type":"tuple"},{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"addLiquidityWMasterChef","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"approved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bank","outputs":[{"internalType":"contract IBank","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"getAndApprovePair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestWMasterChef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pairs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtLPTake","type":"uint256"},{"internalType":"uint256","name":"amtLPWithdraw","type":"uint256"},{"internalType":"uint256","name":"amtARepay","type":"uint256"},{"internalType":"uint256","name":"amtBRepay","type":"uint256"},{"internalType":"uint256","name":"amtLPRepay","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.RepayAmounts","name":"amt","type":"tuple"}],"name":"removeLiquidityWERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"amtLPTake","type":"uint256"},{"internalType":"uint256","name":"amtLPWithdraw","type":"uint256"},{"internalType":"uint256","name":"amtARepay","type":"uint256"},{"internalType":"uint256","name":"amtBRepay","type":"uint256"},{"internalType":"uint256","name":"amtLPRepay","type":"uint256"},{"internalType":"uint256","name":"amtAMin","type":"uint256"},{"internalType":"uint256","name":"amtBMin","type":"uint256"}],"internalType":"struct SushiswapSpellV1.RepayAmounts","name":"amt","type":"tuple"}],"name":"removeLiquidityWMasterChef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pendingGovernor","type":"address"}],"name":"setPendingGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"lpTokens","type":"address[]"},{"internalType":"bool[]","name":"statuses","type":"bool[]"}],"name":"setWhitelistLPTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sushi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"werc20","outputs":[{"internalType":"contract IWERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedLpTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wmasterchef","outputs":[{"internalType":"contract IWMasterChef","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101606040523480156200001257600080fd5b50604051620052c1380380620052c1833981016040819052620000359162000832565b8383836001600160a01b031663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b1580156200007157600080fd5b505afa15801562000086573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ac9190620007f1565b828282620000c16301ffc9a760e01b62000323565b620000d3630271189760e51b62000323565b6001600160601b0319606084811b821660805283811b821660a05282901b1660c0526200010181846200037e565b60405163a22cb46560e01b81526001600160a01b0383169063a22cb4659062000132908690600190600401620008fe565b600060405180830381600087803b1580156200014d57600080fd5b505af115801562000162573d6000803e3d6000fd5b50505050505050620001796200040860201b60201c565b505050816001600160a01b0316610100816001600160a01b031660601b81525050816001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015620001d457600080fd5b505afa158015620001e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020f9190620007f1565b6001600160601b0319606091821b811660e0529082901b166101205260405163a22cb46560e01b81526001600160a01b0382169063a22cb465906200025c908790600190600401620008fe565b600060405180830381600087803b1580156200027757600080fd5b505af11580156200028c573d6000803e3d6000fd5b50505050806001600160a01b0316630a0879036040518163ffffffff1660e01b8152600401602060405180830381600087803b158015620002cc57600080fd5b505af1158015620002e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003079190620007f1565b60601b6001600160601b031916610140525062000b5992505050565b6001600160e01b03198082161415620003595760405162461bcd60e51b8152600401620003509062000967565b60405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff166200040457620003d381600019846001600160a01b0316620004fa60201b62001b34179092919060201c565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555b5050565b604254610100900460ff16806200042457506200042462000608565b8062000433575060425460ff16155b620004525760405162461bcd60e51b81526004016200035090620009e4565b604254610100900460ff161580156200047e576042805460ff1961ff0019909116610100171660011790555b6042805462010000600160b01b0319163362010000810291909117909155604380546001600160a01b03191690556040517fbce074c8369e26e70e1ae2f14fc944da352cfe6f52e2de9572f0c9942a24b7fc91620004dc91620008d0565b60405180910390a18015620004f7576042805461ff00191690555b50565b801580620005895750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90620005339030908690600401620008e4565b60206040518083038186803b1580156200054c57600080fd5b505afa15801562000561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000587919062000899565b155b620005a85760405162461bcd60e51b8152600401620003509062000ab3565b620006038363095ea7b360e01b8484604051602401620005ca92919062000919565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200062616565b505050565b60006200062030620006c260201b62001c331760201c565b15905090565b606062000682826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620006c860201b62001c39179092919060201c565b805190915015620006035780806020019051810190620006a3919062000810565b620006035760405162461bcd60e51b8152600401620003509062000a69565b3b151590565b6060620006d98484600085620006e3565b90505b9392505050565b606082471015620007085760405162461bcd60e51b815260040162000350906200099e565b6200071385620006c2565b620007325760405162461bcd60e51b8152600401620003509062000a32565b60006060866001600160a01b03168587604051620007519190620008b2565b60006040518083038185875af1925050503d806000811462000790576040519150601f19603f3d011682016040523d82523d6000602084013e62000795565b606091505b509092509050620007a8828286620007b3565b979650505050505050565b60608315620007c4575081620006dc565b825115620007d55782518084602001fd5b8160405162461bcd60e51b815260040162000350919062000932565b60006020828403121562000803578081fd5b8151620006dc8162000b43565b60006020828403121562000822578081fd5b81518015158114620006dc578182fd5b6000806000806080858703121562000848578283fd5b8451620008558162000b43565b6020860151909450620008688162000b43565b60408601519093506200087b8162000b43565b60608601519092506200088e8162000b43565b939692955090935050565b600060208284031215620008ab578081fd5b5051919050565b60008251620008c681846020870162000b10565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b03929092168252602082015260400190565b60006020825282518060208401526200095381604085016020870162000b10565b601f01601f19169190910160400192915050565b6020808252601c908201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60005b8381101562000b2d57818101518382015260200162000b13565b8381111562000b3d576000848401525b50505050565b6001600160a01b0381168114620004f757600080fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6145c962000cf86000398061046e5280610c67528061103552806117b3525080610762528061080252806108d9528061096c52806109e15280610af65280610b345280610c045280610d185280610e905280610f235280610f97528061115c5280611366528061140e52806114a1528061151452806115a8528061165152806117365250806105cb52806105f5528061061f5280611b1252806121ae52806122df528061240c5280612c1e5280612de2525080610516528061106f52508061015f52806106a25280612fc5528061306b5280613436525080610caa5280611d3e5280611db25280612e955280612ed05280612f7e5250806106c9528061093f5280610bd75280610cf45280610d4d5280610ef652806112af5280611474528061170952806119055280611c645280611d105280611e595280611f1a5280611fc7528061207452806127bb5280612f4e52806130d6528061339d52806133d852806134c2528061351652506145c96000f3fe60806040526004361061014f5760003560e01c806395723b1c116100b6578063e58bb6391161006f578063e58bb6391461039f578063ee42c6f4146103b4578063f235757f146103d4578063f23a6e61146103f4578063f4b1604514610414578063f887ea4014610434576101a7565b806395723b1c14610302578063bc197c8114610322578063c45a01551461034f578063cc9b188014610364578063e07d904e14610377578063e3056a341461038a576101a7565b806340a65ad21161010857806340a65ad21461026e5780634bab09f6146102835780635741229c146102a357806369454b86146102b857806376cdb03b146102d857806386adcc79146102ed576101a7565b806301ffc9a7146101ac5780630a087903146101e25780630c340a24146102045780631387d96d146102195780632185059f146102395780633fc8cef314610259576101a7565b366101a757336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101a55760405162461bcd60e51b815260040161019c9061426f565b60405180910390fd5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004613d6d565b610449565b6040516101d99190613fa1565b60405180910390f35b3480156101ee57600080fd5b506101f761046c565b6040516101d99190613eb0565b34801561021057600080fd5b506101f7610490565b34801561022557600080fd5b506101a5610234366004613ae6565b6104a5565b34801561024557600080fd5b506101f761025436600461395a565b6104d0565b34801561026557600080fd5b506101f76106a0565b34801561027a57600080fd5b506101a56106c4565b34801561028f57600080fd5b506101cc61029e366004613922565b610c93565b3480156102af57600080fd5b506101f7610ca8565b3480156102c457600080fd5b506101f76102d336600461395a565b610ccc565b3480156102e457600080fd5b506101f7610cf2565b3480156102f957600080fd5b506101f7610d16565b34801561030e57600080fd5b506101a561031d366004613ae6565b610d3a565b34801561032e57600080fd5b5061034261033d366004613992565b611059565b6040516101d99190613fac565b34801561035b57600080fd5b506101f761106d565b6101a5610372366004613a4d565b611091565b6101a5610385366004613a95565b61114a565b34801561039657600080fd5b506101f76117e4565b3480156103ab57600080fd5b506101a56117f3565b3480156103c057600080fd5b506101a56103cf366004613c37565b611883565b3480156103e057600080fd5b506101a56103ef366004613922565b611a58565b34801561040057600080fd5b5061034261040f366004613b7f565b611ade565b34801561042057600080fd5b506101cc61042f36600461395a565b611af0565b34801561044057600080fd5b506101f7611b10565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6042546201000090046001600160a01b031681565b60006104b184846104d0565b90506104be818335611c52565b6104ca84848484611e1d565b50505050565b6001600160a01b0380831660009081526085602090815260408083208585168452909152812054909116806106975760405163e6a4390560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e6a439059061054d9087908790600401613ec4565b60206040518083038186803b15801561056557600080fd5b505afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393e565b90506001600160a01b0381166105c55760405162461bcd60e51b815260040161019c906141e7565b6105ef847f00000000000000000000000000000000000000000000000000000000000000006126b8565b610619837f00000000000000000000000000000000000000000000000000000000000000006126b8565b610643817f00000000000000000000000000000000000000000000000000000000000000006126b8565b6001600160a01b0380851660008181526085602081815260408084208987168552825280842080549688166001600160a01b0319978816811790915592825280842094845293905291902080549092161790555b90505b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561072057600080fd5b505afa158015610734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107589190613b38565b50925092505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dc20c6fa836040518263ffffffff1660e01b81526004016107ac919061447e565b604080518083038186803b1580156107c357600080fd5b505afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190613e01565b50905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a4775772846040518263ffffffff1660e01b815260040161084c919061447e565b60206040518083038186803b15801561086457600080fd5b505afa158015610878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089c919061393e565b6001600160a01b03811660009081526084602052604090205490915060ff166108d75760405162461bcd60e51b815260040161019c90614238565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316146109285760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba89061099a907f000000000000000000000000000000000000000000000000000000000000000090879060001990600401613f80565b600060405180830381600087803b1580156109b457600080fd5b505af11580156109c8573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab9150610a1c908690600019906004016144da565b602060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190613de9565b506040516370a0823160e01b81526000906001600160a01b038316906370a0823190610a9e903090600401613eb0565b60206040518083038186803b158015610ab657600080fd5b505afa158015610aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aee9190613de9565b9050610b1a827f00000000000000000000000000000000000000000000000000000000000000006126b8565b604051630d9778e560e11b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631b2ef1ca90610b6b90879086906004016144da565b602060405180830381600087803b158015610b8557600080fd5b505af1158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613de9565b60405163314568d960e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063314568d990610c30907f00000000000000000000000000000000000000000000000000000000000000009085908790600401613f80565b600060405180830381600087803b158015610c4a57600080fd5b505af1158015610c5e573d6000803e3d6000fd5b50505050610c8b7f000000000000000000000000000000000000000000000000000000000000000061272f565b505050505050565b60846020526000908152604090205460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b60856020908152600092835260408084209091529082529020546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610d4684846104d0565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015610da457600080fd5b505afa158015610db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddc9190613b38565b509250925050826001600160a01b0316826001600160a01b031663a4775772836040518263ffffffff1660e01b8152600401610e18919061447e565b60206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e68919061393e565b6001600160a01b031614610e8e5760405162461bcd60e51b815260040161019c906143b0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614610edf5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba890610f50907f0000000000000000000000000000000000000000000000000000000000000000908590893590600401613f80565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab9150610fd19084908835906004016144da565b602060405180830381600087803b158015610feb57600080fd5b505af1158015610fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110239190613de9565b5061103086868686611e1d565b610c8b7f000000000000000000000000000000000000000000000000000000000000000061272f565b63bc197c8160e01b98975050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061109d84846104d0565b90506110ab8484848461285b565b61113081826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110db9190613eb0565b60206040518083038186803b1580156110f357600080fd5b505afa158015611107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112b9190613de9565b612e89565b611138612fab565b6111418461272f565b6104ca8361272f565b600061115685856104d0565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631fc8bc5d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b357600080fd5b505afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb919061393e565b6001600160a01b0316631526fe27846040518263ffffffff1660e01b8152600401611216919061447e565b60806040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613bf9565b5050509050816001600160a01b0316816001600160a01b03161461129c5760405162461bcd60e51b815260040161019c9061420c565b6112a88686868561285b565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561130657600080fd5b505afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613b38565b919550935091505080156115a257604051636e10637d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc20c6fa9061139b90869060040161447e565b604080518083038186803b1580156113b257600080fd5b505afa1580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea9190613e01565b50905080871461140c5760405162461bcd60e51b815260040161019c90614352565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161461145d5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368eb4ba8906114cd907f00000000000000000000000000000000000000000000000000000000000000009087908790600401613f80565b600060405180830381600087803b1580156114e757600080fd5b505af11580156114fb573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063b390c0ab915061154d90869086906004016144da565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190613de9565b50505b6115cc857f00000000000000000000000000000000000000000000000000000000000000006126b8565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906115fb903090600401613eb0565b60206040518083038186803b15801561161357600080fd5b505afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164b9190613de9565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631b2ef1ca89846040518363ffffffff1660e01b815260040161169d9291906144da565b602060405180830381600087803b1580156116b757600080fd5b505af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190613de9565b60405163314568d960e01b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063314568d990611762907f00000000000000000000000000000000000000000000000000000000000000009085908790600401613f80565b600060405180830381600087803b15801561177c57600080fd5b505af1158015611790573d6000803e3d6000fd5b5050505061179c612fab565b6117a58b61272f565b6117ae8a61272f565b6117d77f000000000000000000000000000000000000000000000000000000000000000061272f565b5050505050505050505050565b6043546001600160a01b031681565b6043546001600160a01b0316331461181d5760405162461bcd60e51b815260040161019c9061401f565b604380546001600160a01b03191690556042805462010000600160b01b03191633620100008102919091179091556040517fd345d81ce68c70b119a17eee79dc1421700bd9cb21ca148a62dc90983964e82f9161187991613eb0565b60405180910390a1565b6042546201000090046001600160a01b031633146118b35760405162461bcd60e51b815260040161019c90614178565b8281146118d25760405162461bcd60e51b815260040161019c906141a2565b60005b83811015611a51578282828181106118e957fe5b90506020020160208101906118fe9190613d35565b156119db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e660cc0886868481811061193e57fe5b90506020020160208101906119539190613922565b6040518263ffffffff1660e01b815260040161196f9190613eb0565b60206040518083038186803b15801561198757600080fd5b505afa15801561199b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bf9190613d51565b6119db5760405162461bcd60e51b815260040161019c9061408d565b8282828181106119e757fe5b90506020020160208101906119fc9190613d35565b60846000878785818110611a0c57fe5b9050602002016020810190611a219190613922565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016118d5565b5050505050565b6042546201000090046001600160a01b03163314611a885760405162461bcd60e51b815260040161019c90614178565b604380546001600160a01b0319166001600160a01b0383161790556040517f964dea888b00b2ab53f13dfe7ca334b46e99338c222ae232d98547a1da019f6090611ad3908390613eb0565b60405180910390a150565b63f23a6e6160e01b9695505050505050565b604160209081526000928352604080842090915290825290205460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000081565b801580611bbc5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b6a9030908690600401613ec4565b60206040518083038186803b158015611b8257600080fd5b505afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190613de9565b155b611bd85760405162461bcd60e51b815260040161019c90614428565b611c2e8363095ea7b360e01b8484604051602401611bf7929190613f67565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131f4565b505050565b3b151590565b6060611c488484600085613283565b90505b9392505050565b8015611e1957600019811415611cf9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015611cbb57600080fd5b505afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf39190613b38565b93505050505b604051630d1d697560e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916368eb4ba891611d6b917f0000000000000000000000000000000000000000000000000000000000000000918716908690600401613f80565b600060405180830381600087803b158015611d8557600080fd5b505af1158015611d99573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250639dc29fac9150611deb9085908590600401613f67565b600060405180830381600087803b158015611e0557600080fd5b505af1158015610c8b573d6000803e3d6000fd5b5050565b6001600160a01b03811660009081526084602052604090205460ff16611e555760405162461bcd60e51b815260040161019c90614238565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d7ac71ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015611eb057600080fd5b505afa158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190613de9565b9050604083013560608401356080850135600019831415611fa6576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c90611f519087908c90600401614487565b602060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190613de9565b92505b600019821415612053576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c90611ffe9087908b90600401614487565b602060405180830381600087803b15801561201857600080fd5b505af115801561202c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120509190613de9565b91505b600019811415612100576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382a2fb9c906120ab9087908990600401614487565b602060405180830381600087803b1580156120c557600080fd5b505af11580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190613de9565b90505b600061218c8760200135876001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016121369190613eb0565b60206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121869190613de9565b90613344565b9050600080821561224757604051635d5155ef60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063baa2abde906121f0908e908e908890600090819030904290600401613ede565b6040805180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122419190613e01565b90925090505b60006122578760a08c013561336c565b905060006122698760c08d013561336c565b9050818410801561227957508083115b156123985760408051600280825260608083018452926020830190803683370190505090508c8e826000815181106122ad57fe5b60200260200101836001815181106122c157fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000000000000000000000000000000000000000000016638803dbee61230e8588613344565b6123188786613344565b8430426040518663ffffffff1660e01b815260040161233b95949392919061449e565b600060405180830381600087803b15801561235557600080fd5b505af1158015612369573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123919190810190613ca0565b50506124c1565b81841180156123a657508083105b156124c15760408051600280825260608083018452926020830190803683370190505090508d8d826000815181106123da57fe5b60200260200101836001815181106123ee57fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000000000000000000000000000000000000000000016638803dbee61243b8487613344565b6124458887613344565b8430426040518663ffffffff1660e01b815260040161246895949392919061449e565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124be9190810190613ca0565b50505b6124cb8d89613391565b6124d58c88613391565b6124df8a87613391565b6040516370a0823160e01b815260a08c0135906001600160a01b038f16906370a0823190612511903090600401613eb0565b60206040518083038186803b15801561252957600080fd5b505afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190613de9565b101561256c57600080fd5b6040516370a0823160e01b815260c08c0135906001600160a01b038e16906370a082319061259e903090600401613eb0565b60206040518083038186803b1580156125b657600080fd5b505afa1580156125ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ee9190613de9565b10156125f957600080fd5b6040516370a0823160e01b815260208c0135906001600160a01b038c16906370a082319061262b903090600401613eb0565b60206040518083038186803b15801561264357600080fd5b505afa158015612657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267b9190613de9565b101561268657600080fd5b61268e612fab565b6126978d61272f565b6126a08c61272f565b6126a98a61272f565b50505050505050505050505050565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff16611e19576126fb6001600160a01b03831682600019611b34565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555050565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061275e903090600401613eb0565b60206040518083038186803b15801561277657600080fd5b505afa15801561278a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ae9190613de9565b90508015611e1957611e197f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281257600080fd5b505afa158015612826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284a919061393e565b6001600160a01b038416908361340f565b6001600160a01b03811660009081526084602052604090205460ff166128935760405162461bcd60e51b815260040161019c90614238565b61289b61342e565b6128a68483356134a5565b6128b48383602001356134a5565b6128c28183604001356134a5565b6128d08483606001356134f9565b6128de8383608001356134f9565b6128ec818360a001356134f9565b6000806000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161291d9190613eb0565b60206040518083038186803b15801561293557600080fd5b505afa158015612949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296d9190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161299d9190613eb0565b60206040518083038186803b1580156129b557600080fd5b505afa1580156129c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ed9190613de9565b9050600080896001600160a01b0316876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d919061393e565b6001600160a01b03161415612b0357866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190613d95565b506001600160701b039182169350169050612b86565b866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612b3c57600080fd5b505afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613d95565b506001600160701b0390811693501690505b612b928484848461354d565b90965094505084159250612cb791505057604080516002808252606080830184529260208301908036833701905050905081612bcf578686612bd2565b85875b82600081518110612bdf57fe5b6020026020010183600181518110612bf357fe5b6001600160a01b0393841660209182029290920101529181169091526040516338ed173960e01b81527f0000000000000000000000000000000000000000000000000000000000000000909116906338ed173990612c5e90869060009086903090429060040161449e565b600060405180830381600087803b158015612c7857600080fd5b505af1158015612c8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cb49190810190613ca0565b50505b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ce6903090600401613eb0565b60206040518083038186803b158015612cfe57600080fd5b505afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612d669190613eb0565b60206040518083038186803b158015612d7e57600080fd5b505afa158015612d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db69190613de9565b90506000821180612dc75750600081115b15612e7f5760405162e8e33760e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e8e3370090612e2d908b908b908790879060c08e01359060e08f01359030904290600401613f1e565b606060405180830381600087803b158015612e4757600080fd5b505af1158015612e5b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d79190613e24565b5050505050505050565b8015611e1957612eb9827f00000000000000000000000000000000000000000000000000000000000000006126b8565b6040516340c10f1960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990612f079085908590600401613f67565b600060405180830381600087803b158015612f2157600080fd5b505af1158015612f35573d6000803e3d6000fd5b505060405163314568d960e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116935063314568d99250611deb917f0000000000000000000000000000000000000000000000000000000000000000918716908690600401613f80565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190612ffa903090600401613eb0565b602060405180830381600087803b15801561301457600080fd5b505af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613de9565b905080156131f157604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906130a090849060040161447e565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561312d57600080fd5b505afa158015613141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613165919061393e565b604080516000815260208101918290526001600160a01b039290921691849161318e9190613e94565b60006040518083038185875af1925050503d80600081146131cb576040519150601f19603f3d011682016040523d82523d6000602084013e6131d0565b606091505b5050905080611e195760405162461bcd60e51b815260040161019c90613ff4565b50565b6060613249826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c399092919063ffffffff16565b805190915015611c2e57808060200190518101906132679190613d51565b611c2e5760405162461bcd60e51b815260040161019c906143de565b6060824710156132a55760405162461bcd60e51b815260040161019c906140fb565b6132ae85611c33565b6132ca5760405162461bcd60e51b815260040161019c90614379565b60006060866001600160a01b031685876040516132e79190613e94565b60006040518083038185875af1925050503d8060008114613324576040519150601f19603f3d011682016040523d82523d6000602084013e613329565b606091505b509150915061333982828661359c565b979650505050505050565b6000828211156133665760405162461bcd60e51b815260040161019c906140c4565b50900390565b6000828201838110156106975760405162461bcd60e51b815260040161019c90614056565b8015611e19576133c1827f00000000000000000000000000000000000000000000000000000000000000006126b8565b604051630450cfaf60e31b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906322867d7890611deb9085908590600401613f67565b611c2e8363a9059cbb60e01b8484604051602401611bf7929190613f67565b34156134a3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561348f57600080fd5b505af1158015611a51573d6000803e3d6000fd5b565b8015611e195760405163246b5de160e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906348d6bbc290611deb9085908590600401613f67565b8015611e1957604051634b8a352960e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634b8a352990611deb9085908590600401613f67565b60008061355a85856135d5565b61356487856135d5565b10613580576135758686868661360f565b915060009050613593565b61358c8587858761360f565b9150600190505b94509492505050565b606083156135ab575081611c4b565b8251156135bb5782518084602001fd5b8160405162461bcd60e51b815260040161019c9190613fc1565b6000826135e45750600061069a565b828202828482816135f157fe5b04146106975760405162461bcd60e51b815260040161019c906142a6565b600061361b84846135d5565b61362586846135d5565b10156136435760405162461bcd60e51b815260040161019c90614330565b6103e560006136546107cd866135d5565b9050600061366f61366588886135d5565b6121868a886135d5565b9050600061369c876136966136848b8a61336c565b613690866103e86135d5565b90613709565b906135d5565b905060006136af600461369687856135d5565b905060006136cf6136ca836136c488806135d5565b9061336c565b61373b565b905060006136dd8287613344565b905060006136ec8860026135d5565b90506136f88282613709565b9d9c50505050505050505050505050565b600080821161372a5760405162461bcd60e51b815260040161019c90614141565b81838161373357fe5b049392505050565b60008161374a57506000610467565b816001600160801b82106137635760809190911c9060401b5b68010000000000000000821061377e5760409190911c9060201b5b64010000000082106137955760209190911c9060101b5b6201000082106137aa5760109190911c9060081b5b61010082106137be5760089190911c9060041b5b601082106137d15760049190911c9060021b5b600882106137dd5760011b5b60018185816137e857fe5b048201901c905060018185816137fa57fe5b048201901c9050600181858161380c57fe5b048201901c9050600181858161381e57fe5b048201901c9050600181858161383057fe5b048201901c9050600181858161384257fe5b048201901c9050600181858161385457fe5b048201901c9050600081858161386657fe5b0490508082106138765780613878565b815b95945050505050565b60008083601f840112613892578182fd5b50813567ffffffffffffffff8111156138a9578182fd5b60208301915083602080830285010111156138c357600080fd5b9250929050565b60008083601f8401126138db578182fd5b50813567ffffffffffffffff8111156138f2578182fd5b6020830191508360208285010111156138c357600080fd5b6000610100828403121561391c578081fd5b50919050565b600060208284031215613933578081fd5b81356106978161455b565b60006020828403121561394f578081fd5b81516106978161455b565b6000806040838503121561396c578081fd5b82356139778161455b565b915060208301356139878161455b565b809150509250929050565b60008060008060008060008060a0898b0312156139ad578384fd5b88356139b88161455b565b975060208901356139c88161455b565b9650604089013567ffffffffffffffff808211156139e4578586fd5b6139f08c838d01613881565b909850965060608b0135915080821115613a08578586fd5b613a148c838d01613881565b909650945060808b0135915080821115613a2c578384fd5b50613a398b828c016138ca565b999c989b5096995094979396929594505050565b60008060006101408486031215613a62578283fd5b8335613a6d8161455b565b92506020840135613a7d8161455b565b9150613a8c856040860161390a565b90509250925092565b6000806000806101608587031215613aab578384fd5b8435613ab68161455b565b93506020850135613ac68161455b565b9250613ad5866040870161390a565b939692955092936101400135925050565b6000806000838503610120811215613afc578384fd5b8435613b078161455b565b93506020850135613b178161455b565b925060e0603f1982011215613b2a578182fd5b506040840190509250925092565b60008060008060808587031215613b4d578182fd5b8451613b588161455b565b6020860151909450613b698161455b565b6040860151606090960151949790965092505050565b60008060008060008060a08789031215613b97578384fd5b8635613ba28161455b565b95506020870135613bb28161455b565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bdb578283fd5b613be789828a016138ca565b979a9699509497509295939492505050565b60008060008060808587031215613c0e578182fd5b8451613c198161455b565b60208601516040870151606090970151919890975090945092505050565b60008060008060408587031215613c4c578182fd5b843567ffffffffffffffff80821115613c63578384fd5b613c6f88838901613881565b90965094506020870135915080821115613c87578384fd5b50613c9487828801613881565b95989497509550505050565b60006020808385031215613cb2578182fd5b825167ffffffffffffffff811115613cc8578283fd5b8301601f81018513613cd8578283fd5b8051613ceb613ce68261450f565b6144e8565b8181528381019083850185840285018601891015613d07578687fd5b8694505b83851015613d29578051835260019490940193918501918501613d0b565b50979650505050505050565b600060208284031215613d46578081fd5b813561069781614570565b600060208284031215613d62578081fd5b815161069781614570565b600060208284031215613d7e578081fd5b81356001600160e01b031981168114610697578182fd5b600080600060608486031215613da9578081fd5b8351613db48161457e565b6020850151909350613dc58161457e565b604085015190925063ffffffff81168114613dde578182fd5b809150509250925092565b600060208284031215613dfa578081fd5b5051919050565b60008060408385031215613e13578182fd5b505080516020909101519092909150565b600080600060608486031215613e38578081fd5b8351925060208401519150604084015190509250925092565b6000815180845260208085019450808401835b83811015613e895781516001600160a01b031687529582019590820190600101613e64565b509495945050505050565b60008251613ea681846020870161452f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6001600160a01b039889168152968816602088015260408701959095526060860193909352608085019190915260a084015290921660c082015260e08101919091526101000190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6001600160e01b031991909116815260200190565b6000602082528251806020840152613fe081604085016020870161452f565b601f01601f19169190910160400192915050565b6020808252601190820152701c99599d5b99081155120819985a5b1959607a1b604082015260600190565b60208082526018908201527f6e6f74207468652070656e64696e6720676f7665726e6f720000000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601b908201527f6f7261636c65206e6f7420737570706f7274206c7020746f6b656e0000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b60208082526010908201526f3737ba103a34329033b7bb32b93737b960811b604082015260600190565b60208082526025908201527f6c70546f6b656e732026207374617475736573206c656e677468206d69736d616040820152641d18da195960da1b606082015260800190565b6020808252600b908201526a3737903638103a37b5b2b760a91b604082015260600190565b60208082526012908201527134b731b7b93932b1ba103638103a37b5b2b760711b604082015260600190565b60208082526018908201527f6c7020746f6b656e206e6f742077686974656c69737465640000000000000000604082015260600190565b60208082526017908201527f455448206d75737420636f6d652066726f6d2057455448000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526029908201527f636f6c6c61746572616c20746f6b656e202620776d617374657263686566206d6040820152681a5cdb585d18da195960ba1b606082015260800190565b60208082526008908201526714995d995c9cd95960c21b604082015260600190565b6020808252600d908201526c1a5b98dbdc9c9958dd081c1a59609a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b602080825260149082015273696e636f727265637420756e6465726c79696e6760601b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9182526001600160a01b0316602082015260400190565b600086825285602083015260a060408301526144bd60a0830186613e51565b6001600160a01b0394909416606083015250608001529392505050565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561450757600080fd5b604052919050565b600067ffffffffffffffff821115614525578081fd5b5060209081020190565b60005b8381101561454a578181015183820152602001614532565b838111156104ca5750506000910152565b6001600160a01b03811681146131f157600080fd5b80151581146131f157600080fd5b6001600160701b03811681146131f157600080fdfea2646970667358221220d5c29f7024c1786530ba760dd3ab0666c5d8eb0af8bb5acc5509dbf76873090064736f6c634300060c0033000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60
Deployed Bytecode
0x60806040526004361061014f5760003560e01c806395723b1c116100b6578063e58bb6391161006f578063e58bb6391461039f578063ee42c6f4146103b4578063f235757f146103d4578063f23a6e61146103f4578063f4b1604514610414578063f887ea4014610434576101a7565b806395723b1c14610302578063bc197c8114610322578063c45a01551461034f578063cc9b188014610364578063e07d904e14610377578063e3056a341461038a576101a7565b806340a65ad21161010857806340a65ad21461026e5780634bab09f6146102835780635741229c146102a357806369454b86146102b857806376cdb03b146102d857806386adcc79146102ed576101a7565b806301ffc9a7146101ac5780630a087903146101e25780630c340a24146102045780631387d96d146102195780632185059f146102395780633fc8cef314610259576101a7565b366101a757336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101a55760405162461bcd60e51b815260040161019c9061426f565b60405180910390fd5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004613d6d565b610449565b6040516101d99190613fa1565b60405180910390f35b3480156101ee57600080fd5b506101f761046c565b6040516101d99190613eb0565b34801561021057600080fd5b506101f7610490565b34801561022557600080fd5b506101a5610234366004613ae6565b6104a5565b34801561024557600080fd5b506101f761025436600461395a565b6104d0565b34801561026557600080fd5b506101f76106a0565b34801561027a57600080fd5b506101a56106c4565b34801561028f57600080fd5b506101cc61029e366004613922565b610c93565b3480156102af57600080fd5b506101f7610ca8565b3480156102c457600080fd5b506101f76102d336600461395a565b610ccc565b3480156102e457600080fd5b506101f7610cf2565b3480156102f957600080fd5b506101f7610d16565b34801561030e57600080fd5b506101a561031d366004613ae6565b610d3a565b34801561032e57600080fd5b5061034261033d366004613992565b611059565b6040516101d99190613fac565b34801561035b57600080fd5b506101f761106d565b6101a5610372366004613a4d565b611091565b6101a5610385366004613a95565b61114a565b34801561039657600080fd5b506101f76117e4565b3480156103ab57600080fd5b506101a56117f3565b3480156103c057600080fd5b506101a56103cf366004613c37565b611883565b3480156103e057600080fd5b506101a56103ef366004613922565b611a58565b34801561040057600080fd5b5061034261040f366004613b7f565b611ade565b34801561042057600080fd5b506101cc61042f36600461395a565b611af0565b34801561044057600080fd5b506101f7611b10565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe281565b6042546201000090046001600160a01b031681565b60006104b184846104d0565b90506104be818335611c52565b6104ca84848484611e1d565b50505050565b6001600160a01b0380831660009081526085602090815260408083208585168452909152812054909116806106975760405163e6a4390560e01b81526001600160a01b037f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac169063e6a439059061054d9087908790600401613ec4565b60206040518083038186803b15801561056557600080fd5b505afa158015610579573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059d919061393e565b90506001600160a01b0381166105c55760405162461bcd60e51b815260040161019c906141e7565b6105ef847f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b610619837f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b610643817f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f6126b8565b6001600160a01b0380851660008181526085602081815260408084208987168552825280842080549688166001600160a01b0319978816811790915592825280842094845293905291902080549092161790555b90505b92915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000807f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561072057600080fd5b505afa158015610734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107589190613b38565b50925092505060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b031663dc20c6fa836040518263ffffffff1660e01b81526004016107ac919061447e565b604080518083038186803b1580156107c357600080fd5b505afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190613e01565b50905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b031663a4775772846040518263ffffffff1660e01b815260040161084c919061447e565b60206040518083038186803b15801561086457600080fd5b505afa158015610878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089c919061393e565b6001600160a01b03811660009081526084602052604090205490915060ff166108d75760405162461bcd60e51b815260040161019c90614238565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316846001600160a01b0316146109285760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba89061099a907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6090879060001990600401613f80565b600060405180830381600087803b1580156109b457600080fd5b505af11580156109c8573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab9150610a1c908690600019906004016144da565b602060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190613de9565b506040516370a0823160e01b81526000906001600160a01b038316906370a0823190610a9e903090600401613eb0565b60206040518083038186803b158015610ab657600080fd5b505afa158015610aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aee9190613de9565b9050610b1a827f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606126b8565b604051630d9778e560e11b81526000906001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb601690631b2ef1ca90610b6b90879086906004016144da565b602060405180830381600087803b158015610b8557600080fd5b505af1158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbd9190613de9565b60405163314568d960e01b81529091506001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b169063314568d990610c30907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609085908790600401613f80565b600060405180830381600087803b158015610c4a57600080fd5b505af1158015610c5e573d6000803e3d6000fd5b50505050610c8b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b505050505050565b60846020526000908152604090205460ff1681565b7f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a381565b60856020908152600092835260408084209091529082529020546001600160a01b031681565b7f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b81565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6081565b6000610d4684846104d0565b90506000807f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015610da457600080fd5b505afa158015610db8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ddc9190613b38565b509250925050826001600160a01b0316826001600160a01b031663a4775772836040518263ffffffff1660e01b8152600401610e18919061447e565b60206040518083038186803b158015610e3057600080fd5b505afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e68919061393e565b6001600160a01b031614610e8e5760405162461bcd60e51b815260040161019c906143b0565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316826001600160a01b031614610edf5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba890610f50907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60908590893590600401613f80565b600060405180830381600087803b158015610f6a57600080fd5b505af1158015610f7e573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab9150610fd19084908835906004016144da565b602060405180830381600087803b158015610feb57600080fd5b505af1158015610fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110239190613de9565b5061103086868686611e1d565b610c8b7f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b63bc197c8160e01b98975050505050505050565b7f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac81565b600061109d84846104d0565b90506110ab8484848461285b565b61113081826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016110db9190613eb0565b60206040518083038186803b1580156110f357600080fd5b505afa158015611107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112b9190613de9565b612e89565b611138612fab565b6111418461272f565b6104ca8361272f565b600061115685856104d0565b905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316631fc8bc5d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b357600080fd5b505afa1580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb919061393e565b6001600160a01b0316631526fe27846040518263ffffffff1660e01b8152600401611216919061447e565b60806040518083038186803b15801561122e57600080fd5b505afa158015611242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112669190613bf9565b5050509050816001600160a01b0316816001600160a01b03161461129c5760405162461bcd60e51b815260040161019c9061420c565b6112a88686868561285b565b60008060007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b15801561130657600080fd5b505afa15801561131a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133e9190613b38565b919550935091505080156115a257604051636e10637d60e11b81526000906001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60169063dc20c6fa9061139b90869060040161447e565b604080518083038186803b1580156113b257600080fd5b505afa1580156113c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ea9190613e01565b50905080871461140c5760405162461bcd60e51b815260040161019c90614352565b7f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316846001600160a01b03161461145d5760405162461bcd60e51b815260040161019c906142e7565b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906368eb4ba8906114cd907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609087908790600401613f80565b600060405180830381600087803b1580156114e757600080fd5b505af11580156114fb573d6000803e3d6000fd5b505060405163b390c0ab60e01b81526001600160a01b037f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb6016925063b390c0ab915061154d90869086906004016144da565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190613de9565b50505b6115cc857f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606126b8565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906115fb903090600401613eb0565b60206040518083038186803b15801561161357600080fd5b505afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164b9190613de9565b905060007f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb606001600160a01b0316631b2ef1ca89846040518363ffffffff1660e01b815260040161169d9291906144da565b602060405180830381600087803b1580156116b757600080fd5b505af11580156116cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ef9190613de9565b60405163314568d960e01b81529091506001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b169063314568d990611762907f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb609085908790600401613f80565b600060405180830381600087803b15801561177c57600080fd5b505af1158015611790573d6000803e3d6000fd5b5050505061179c612fab565b6117a58b61272f565b6117ae8a61272f565b6117d77f0000000000000000000000006b3595068778dd592e39a122f4f5a5cf09c90fe261272f565b5050505050505050505050565b6043546001600160a01b031681565b6043546001600160a01b0316331461181d5760405162461bcd60e51b815260040161019c9061401f565b604380546001600160a01b03191690556042805462010000600160b01b03191633620100008102919091179091556040517fd345d81ce68c70b119a17eee79dc1421700bd9cb21ca148a62dc90983964e82f9161187991613eb0565b60405180910390a1565b6042546201000090046001600160a01b031633146118b35760405162461bcd60e51b815260040161019c90614178565b8281146118d25760405162461bcd60e51b815260040161019c906141a2565b60005b83811015611a51578282828181106118e957fe5b90506020020160208101906118fe9190613d35565b156119db577f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663e660cc0886868481811061193e57fe5b90506020020160208101906119539190613922565b6040518263ffffffff1660e01b815260040161196f9190613eb0565b60206040518083038186803b15801561198757600080fd5b505afa15801561199b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119bf9190613d51565b6119db5760405162461bcd60e51b815260040161019c9061408d565b8282828181106119e757fe5b90506020020160208101906119fc9190613d35565b60846000878785818110611a0c57fe5b9050602002016020810190611a219190613922565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790556001016118d5565b5050505050565b6042546201000090046001600160a01b03163314611a885760405162461bcd60e51b815260040161019c90614178565b604380546001600160a01b0319166001600160a01b0383161790556040517f964dea888b00b2ab53f13dfe7ca334b46e99338c222ae232d98547a1da019f6090611ad3908390613eb0565b60405180910390a150565b63f23a6e6160e01b9695505050505050565b604160209081526000928352604080842090915290825290205460ff1681565b7f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b801580611bbc5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b6a9030908690600401613ec4565b60206040518083038186803b158015611b8257600080fd5b505afa158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba9190613de9565b155b611bd85760405162461bcd60e51b815260040161019c90614428565b611c2e8363095ea7b360e01b8484604051602401611bf7929190613f67565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131f4565b505050565b3b151590565b6060611c488484600085613283565b90505b9392505050565b8015611e1957600019811415611cf9577f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663f70aedd96040518163ffffffff1660e01b815260040160806040518083038186803b158015611cbb57600080fd5b505afa158015611ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf39190613b38565b93505050505b604051630d1d697560e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b8116916368eb4ba891611d6b917f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3918716908690600401613f80565b600060405180830381600087803b158015611d8557600080fd5b505af1158015611d99573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b037f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3169250639dc29fac9150611deb9085908590600401613f67565b600060405180830381600087803b158015611e0557600080fd5b505af1158015610c8b573d6000803e3d6000fd5b5050565b6001600160a01b03811660009081526084602052604090205460ff16611e555760405162461bcd60e51b815260040161019c90614238565b60007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663d7ac71ff6040518163ffffffff1660e01b815260040160206040518083038186803b158015611eb057600080fd5b505afa158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190613de9565b9050604083013560608401356080850135600019831415611fa6576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c90611f519087908c90600401614487565b602060405180830381600087803b158015611f6b57600080fd5b505af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa39190613de9565b92505b600019821415612053576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c90611ffe9087908b90600401614487565b602060405180830381600087803b15801561201857600080fd5b505af115801561202c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120509190613de9565b91505b600019811415612100576040516320a8bee760e21b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906382a2fb9c906120ab9087908990600401614487565b602060405180830381600087803b1580156120c557600080fd5b505af11580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190613de9565b90505b600061218c8760200135876001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016121369190613eb0565b60206040518083038186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121869190613de9565b90613344565b9050600080821561224757604051635d5155ef60e11b81526001600160a01b037f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f169063baa2abde906121f0908e908e908890600090819030904290600401613ede565b6040805180830381600087803b15801561220957600080fd5b505af115801561221d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122419190613e01565b90925090505b60006122578760a08c013561336c565b905060006122698760c08d013561336c565b9050818410801561227957508083115b156123985760408051600280825260608083018452926020830190803683370190505090508c8e826000815181106122ad57fe5b60200260200101836001815181106122c157fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f16638803dbee61230e8588613344565b6123188786613344565b8430426040518663ffffffff1660e01b815260040161233b95949392919061449e565b600060405180830381600087803b15801561235557600080fd5b505af1158015612369573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123919190810190613ca0565b50506124c1565b81841180156123a657508083105b156124c15760408051600280825260608083018452926020830190803683370190505090508d8d826000815181106123da57fe5b60200260200101836001815181106123ee57fe5b6001600160a01b0393841660209182029290920101529181169091527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f16638803dbee61243b8487613344565b6124458887613344565b8430426040518663ffffffff1660e01b815260040161246895949392919061449e565b600060405180830381600087803b15801561248257600080fd5b505af1158015612496573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124be9190810190613ca0565b50505b6124cb8d89613391565b6124d58c88613391565b6124df8a87613391565b6040516370a0823160e01b815260a08c0135906001600160a01b038f16906370a0823190612511903090600401613eb0565b60206040518083038186803b15801561252957600080fd5b505afa15801561253d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125619190613de9565b101561256c57600080fd5b6040516370a0823160e01b815260c08c0135906001600160a01b038e16906370a082319061259e903090600401613eb0565b60206040518083038186803b1580156125b657600080fd5b505afa1580156125ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ee9190613de9565b10156125f957600080fd5b6040516370a0823160e01b815260208c0135906001600160a01b038c16906370a082319061262b903090600401613eb0565b60206040518083038186803b15801561264357600080fd5b505afa158015612657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267b9190613de9565b101561268657600080fd5b61268e612fab565b6126978d61272f565b6126a08c61272f565b6126a98a61272f565b50505050505050505050505050565b6001600160a01b0380831660009081526041602090815260408083209385168352929052205460ff16611e19576126fb6001600160a01b03831682600019611b34565b6001600160a01b038083166000908152604160209081526040808320938516835292905220805460ff191660011790555050565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061275e903090600401613eb0565b60206040518083038186803b15801561277657600080fd5b505afa15801561278a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ae9190613de9565b90508015611e1957611e197f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281257600080fd5b505afa158015612826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284a919061393e565b6001600160a01b038416908361340f565b6001600160a01b03811660009081526084602052604090205460ff166128935760405162461bcd60e51b815260040161019c90614238565b61289b61342e565b6128a68483356134a5565b6128b48383602001356134a5565b6128c28183604001356134a5565b6128d08483606001356134f9565b6128de8383608001356134f9565b6128ec818360a001356134f9565b6000806000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161291d9190613eb0565b60206040518083038186803b15801561293557600080fd5b505afa158015612949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296d9190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161299d9190613eb0565b60206040518083038186803b1580156129b557600080fd5b505afa1580156129c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ed9190613de9565b9050600080896001600160a01b0316876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d919061393e565b6001600160a01b03161415612b0357866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612ab557600080fd5b505afa158015612ac9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aed9190613d95565b506001600160701b039182169350169050612b86565b866001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015612b3c57600080fd5b505afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613d95565b506001600160701b0390811693501690505b612b928484848461354d565b90965094505084159250612cb791505057604080516002808252606080830184529260208301908036833701905050905081612bcf578686612bd2565b85875b82600081518110612bdf57fe5b6020026020010183600181518110612bf357fe5b6001600160a01b0393841660209182029290920101529181169091526040516338ed173960e01b81527f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f909116906338ed173990612c5e90869060009086903090429060040161449e565b600060405180830381600087803b158015612c7857600080fd5b505af1158015612c8c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cb49190810190613ca0565b50505b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190612ce6903090600401613eb0565b60206040518083038186803b158015612cfe57600080fd5b505afa158015612d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d369190613de9565b90506000866001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612d669190613eb0565b60206040518083038186803b158015612d7e57600080fd5b505afa158015612d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db69190613de9565b90506000821180612dc75750600081115b15612e7f5760405162e8e33760e81b81526001600160a01b037f000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f169063e8e3370090612e2d908b908b908790879060c08e01359060e08f01359030904290600401613f1e565b606060405180830381600087803b158015612e4757600080fd5b505af1158015612e5b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d79190613e24565b5050505050505050565b8015611e1957612eb9827f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a36126b8565b6040516340c10f1960e01b81526001600160a01b037f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a316906340c10f1990612f079085908590600401613f67565b600060405180830381600087803b158015612f2157600080fd5b505af1158015612f35573d6000803e3d6000fd5b505060405163314568d960e01b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b8116935063314568d99250611deb917f00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3918716908690600401613f80565b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190612ffa903090600401613eb0565b602060405180830381600087803b15801561301457600080fd5b505af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c9190613de9565b905080156131f157604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906130a090849060040161447e565b600060405180830381600087803b1580156130ba57600080fd5b505af11580156130ce573d6000803e3d6000fd5b5050505060007f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6001600160a01b031663630dc7cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561312d57600080fd5b505afa158015613141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613165919061393e565b604080516000815260208101918290526001600160a01b039290921691849161318e9190613e94565b60006040518083038185875af1925050503d80600081146131cb576040519150601f19603f3d011682016040523d82523d6000602084013e6131d0565b606091505b5050905080611e195760405162461bcd60e51b815260040161019c90613ff4565b50565b6060613249826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c399092919063ffffffff16565b805190915015611c2e57808060200190518101906132679190613d51565b611c2e5760405162461bcd60e51b815260040161019c906143de565b6060824710156132a55760405162461bcd60e51b815260040161019c906140fb565b6132ae85611c33565b6132ca5760405162461bcd60e51b815260040161019c90614379565b60006060866001600160a01b031685876040516132e79190613e94565b60006040518083038185875af1925050503d8060008114613324576040519150601f19603f3d011682016040523d82523d6000602084013e613329565b606091505b509150915061333982828661359c565b979650505050505050565b6000828211156133665760405162461bcd60e51b815260040161019c906140c4565b50900390565b6000828201838110156106975760405162461bcd60e51b815260040161019c90614056565b8015611e19576133c1827f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b6126b8565b604051630450cfaf60e31b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906322867d7890611deb9085908590600401613f67565b611c2e8363a9059cbb60e01b8484604051602401611bf7929190613f67565b34156134a3577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561348f57600080fd5b505af1158015611a51573d6000803e3d6000fd5b565b8015611e195760405163246b5de160e11b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b16906348d6bbc290611deb9085908590600401613f67565b8015611e1957604051634b8a352960e01b81526001600160a01b037f000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b1690634b8a352990611deb9085908590600401613f67565b60008061355a85856135d5565b61356487856135d5565b10613580576135758686868661360f565b915060009050613593565b61358c8587858761360f565b9150600190505b94509492505050565b606083156135ab575081611c4b565b8251156135bb5782518084602001fd5b8160405162461bcd60e51b815260040161019c9190613fc1565b6000826135e45750600061069a565b828202828482816135f157fe5b04146106975760405162461bcd60e51b815260040161019c906142a6565b600061361b84846135d5565b61362586846135d5565b10156136435760405162461bcd60e51b815260040161019c90614330565b6103e560006136546107cd866135d5565b9050600061366f61366588886135d5565b6121868a886135d5565b9050600061369c876136966136848b8a61336c565b613690866103e86135d5565b90613709565b906135d5565b905060006136af600461369687856135d5565b905060006136cf6136ca836136c488806135d5565b9061336c565b61373b565b905060006136dd8287613344565b905060006136ec8860026135d5565b90506136f88282613709565b9d9c50505050505050505050505050565b600080821161372a5760405162461bcd60e51b815260040161019c90614141565b81838161373357fe5b049392505050565b60008161374a57506000610467565b816001600160801b82106137635760809190911c9060401b5b68010000000000000000821061377e5760409190911c9060201b5b64010000000082106137955760209190911c9060101b5b6201000082106137aa5760109190911c9060081b5b61010082106137be5760089190911c9060041b5b601082106137d15760049190911c9060021b5b600882106137dd5760011b5b60018185816137e857fe5b048201901c905060018185816137fa57fe5b048201901c9050600181858161380c57fe5b048201901c9050600181858161381e57fe5b048201901c9050600181858161383057fe5b048201901c9050600181858161384257fe5b048201901c9050600181858161385457fe5b048201901c9050600081858161386657fe5b0490508082106138765780613878565b815b95945050505050565b60008083601f840112613892578182fd5b50813567ffffffffffffffff8111156138a9578182fd5b60208301915083602080830285010111156138c357600080fd5b9250929050565b60008083601f8401126138db578182fd5b50813567ffffffffffffffff8111156138f2578182fd5b6020830191508360208285010111156138c357600080fd5b6000610100828403121561391c578081fd5b50919050565b600060208284031215613933578081fd5b81356106978161455b565b60006020828403121561394f578081fd5b81516106978161455b565b6000806040838503121561396c578081fd5b82356139778161455b565b915060208301356139878161455b565b809150509250929050565b60008060008060008060008060a0898b0312156139ad578384fd5b88356139b88161455b565b975060208901356139c88161455b565b9650604089013567ffffffffffffffff808211156139e4578586fd5b6139f08c838d01613881565b909850965060608b0135915080821115613a08578586fd5b613a148c838d01613881565b909650945060808b0135915080821115613a2c578384fd5b50613a398b828c016138ca565b999c989b5096995094979396929594505050565b60008060006101408486031215613a62578283fd5b8335613a6d8161455b565b92506020840135613a7d8161455b565b9150613a8c856040860161390a565b90509250925092565b6000806000806101608587031215613aab578384fd5b8435613ab68161455b565b93506020850135613ac68161455b565b9250613ad5866040870161390a565b939692955092936101400135925050565b6000806000838503610120811215613afc578384fd5b8435613b078161455b565b93506020850135613b178161455b565b925060e0603f1982011215613b2a578182fd5b506040840190509250925092565b60008060008060808587031215613b4d578182fd5b8451613b588161455b565b6020860151909450613b698161455b565b6040860151606090960151949790965092505050565b60008060008060008060a08789031215613b97578384fd5b8635613ba28161455b565b95506020870135613bb28161455b565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bdb578283fd5b613be789828a016138ca565b979a9699509497509295939492505050565b60008060008060808587031215613c0e578182fd5b8451613c198161455b565b60208601516040870151606090970151919890975090945092505050565b60008060008060408587031215613c4c578182fd5b843567ffffffffffffffff80821115613c63578384fd5b613c6f88838901613881565b90965094506020870135915080821115613c87578384fd5b50613c9487828801613881565b95989497509550505050565b60006020808385031215613cb2578182fd5b825167ffffffffffffffff811115613cc8578283fd5b8301601f81018513613cd8578283fd5b8051613ceb613ce68261450f565b6144e8565b8181528381019083850185840285018601891015613d07578687fd5b8694505b83851015613d29578051835260019490940193918501918501613d0b565b50979650505050505050565b600060208284031215613d46578081fd5b813561069781614570565b600060208284031215613d62578081fd5b815161069781614570565b600060208284031215613d7e578081fd5b81356001600160e01b031981168114610697578182fd5b600080600060608486031215613da9578081fd5b8351613db48161457e565b6020850151909350613dc58161457e565b604085015190925063ffffffff81168114613dde578182fd5b809150509250925092565b600060208284031215613dfa578081fd5b5051919050565b60008060408385031215613e13578182fd5b505080516020909101519092909150565b600080600060608486031215613e38578081fd5b8351925060208401519150604084015190509250925092565b6000815180845260208085019450808401835b83811015613e895781516001600160a01b031687529582019590820190600101613e64565b509495945050505050565b60008251613ea681846020870161452f565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6001600160a01b039889168152968816602088015260408701959095526060860193909352608085019190915260a084015290921660c082015260e08101919091526101000190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b901515815260200190565b6001600160e01b031991909116815260200190565b6000602082528251806020840152613fe081604085016020870161452f565b601f01601f19169190910160400192915050565b6020808252601190820152701c99599d5b99081155120819985a5b1959607a1b604082015260600190565b60208082526018908201527f6e6f74207468652070656e64696e6720676f7665726e6f720000000000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601b908201527f6f7261636c65206e6f7420737570706f7274206c7020746f6b656e0000000000604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b60208082526010908201526f3737ba103a34329033b7bb32b93737b960811b604082015260600190565b60208082526025908201527f6c70546f6b656e732026207374617475736573206c656e677468206d69736d616040820152641d18da195960da1b606082015260800190565b6020808252600b908201526a3737903638103a37b5b2b760a91b604082015260600190565b60208082526012908201527134b731b7b93932b1ba103638103a37b5b2b760711b604082015260600190565b60208082526018908201527f6c7020746f6b656e206e6f742077686974656c69737465640000000000000000604082015260600190565b60208082526017908201527f455448206d75737420636f6d652066726f6d2057455448000000000000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526029908201527f636f6c6c61746572616c20746f6b656e202620776d617374657263686566206d6040820152681a5cdb585d18da195960ba1b606082015260800190565b60208082526008908201526714995d995c9cd95960c21b604082015260600190565b6020808252600d908201526c1a5b98dbdc9c9958dd081c1a59609a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b602080825260149082015273696e636f727265637420756e6465726c79696e6760601b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9182526001600160a01b0316602082015260400190565b600086825285602083015260a060408301526144bd60a0830186613e51565b6001600160a01b0394909416606083015250608001529392505050565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561450757600080fd5b604052919050565b600067ffffffffffffffff821115614525578081fd5b5060209081020190565b60005b8381101561454a578181015183820152602001614532565b838111156104ca5750506000910152565b6001600160a01b03811681146131f157600080fd5b80151581146131f157600080fd5b6001600160701b03811681146131f157600080fdfea2646970667358221220d5c29f7024c1786530ba760dd3ab0666c5d8eb0af8bb5acc5509dbf76873090064736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60
-----Decoded View---------------
Arg [0] : _bank (address): 0xba5eBAf3fc1Fcca67147050Bf80462393814E54B
Arg [1] : _werc20 (address): 0x06799a1e4792001AA9114F0012b9650cA28059a3
Arg [2] : _router (address): 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F
Arg [3] : _wmasterchef (address): 0xA2caEa05fF7B98f10Ad5ddc837F15905f33FEb60
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba5ebaf3fc1fcca67147050bf80462393814e54b
Arg [1] : 00000000000000000000000006799a1e4792001aa9114f0012b9650ca28059a3
Arg [2] : 000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f
Arg [3] : 000000000000000000000000a2caea05ff7b98f10ad5ddc837f15905f33feb60
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.