Overview
frxETH Balance | FXTL Balance
0 frxETH | 0 FXTL
frxETH Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Source Code Verified (Exact Match) This is an ERC-5202 Blueprint contract
Contract Name:
CurveStableSwapMetaNG
Compiler Version
vyper:0.3.10
Contract Source Code (Vyper language format)
# pragma version 0.3.10 # pragma optimize codesize # pragma evm-version paris """ @title CurveStableSwapMetaNG @author Curve.Fi @license Copyright (c) Curve.Fi, 2020-2023 - all rights reserved @notice Stableswap Metapool implementation for 2 coins. Supports pegged assets. @dev Metapools are pools where the coin on index 1 is a liquidity pool token of another pool. This exposes methods such as exchange_underlying, which exchanges token 0 <> token b1, b2, .. bn, where b is base pool and bn is the nth coin index of the base pool. CAUTION: Does not work if base pool is an NG pool. Use a different metapool implementation index in the factory. Asset Types: 0. Standard ERC20 token with no additional features. Note: Users are advised to do careful due-diligence on ERC20 tokens that they interact with, as this contract cannot differentiate between harmless and malicious ERC20 tokens. 1. Oracle - token with rate oracle (e.g. wstETH) Note: Oracles may be controlled externally by an EOA. Users are advised to proceed with caution. 2. Rebasing - token with rebase (e.g. stETH). Note: Users and Integrators are advised to understand how the AMM contract works with rebasing balances. 3. ERC4626 - token with convertToAssets method (e.g. sDAI). Note: Some ERC4626 implementations may be susceptible to Donation/Inflation attacks. Users are advised to proceed with caution. NOTE: Pool Cannot support tokens with multiple asset types: e.g. ERC4626 with fees are not supported. Supports: 1. ERC20 support for return True/revert, return True/False, return None 2. ERC20 tokens can have arbitrary decimals (<=18). 3. ERC20 tokens that rebase (either positive or fee on transfer) 4. ERC20 tokens that have a rate oracle (e.g. wstETH, cbETH, sDAI, etc.) Note: Oracle precision _must_ be 10**18. 5. ERC4626 tokens with arbitrary precision (<=18) of Vault token and underlying asset. Additional features include: 1. Adds oracles based on AMM State Price (and _not_ last traded price). State prices are calculated _after_ liquidity operations, using bonding curve math. 2. Adds an exponential moving average oracle for D. 3. `exchange_received`: swaps that expect an ERC20 transfer to have occurred prior to executing the swap. Note: a. If pool contains rebasing tokens and one of the `asset_types` is 2 (Rebasing) then calling `exchange_received` will REVERT. b. If pool contains rebasing token and `asset_types` does not contain 2 (Rebasing) then this is an incorrect implementation and rebases can be stolen. 4. Adds `get_dx`, `get_dx_underlying`: Similar to `get_dy` which returns an expected output of coin[j] for given `dx` amount of coin[i], `get_dx` returns expected input of coin[i] for an output amount of coin[j]. 5. Fees are dynamic: AMM will charge a higher fee if pool depegs. This can cause very slight discrepancies between calculated fees and realised fees. """ from vyper.interfaces import ERC20 from vyper.interfaces import ERC20Detailed from vyper.interfaces import ERC4626 implements: ERC20 # ------------------------------- Interfaces --------------------------------- interface Factory: def fee_receiver() -> address: view def admin() -> address: view def views_implementation() -> address: view interface ERC1271: def isValidSignature(_hash: bytes32, _signature: Bytes[65]) -> bytes32: view interface StableSwapViews: def get_dx(i: int128, j: int128, dy: uint256, pool: address) -> uint256: view def get_dy(i: int128, j: int128, dx: uint256, pool: address) -> uint256: view def get_dx_underlying(i: int128, j: int128, dy: uint256, pool: address) -> uint256: view def get_dy_underlying(i: int128, j: int128, dx: uint256, pool: address) -> uint256: view def dynamic_fee(i: int128, j: int128, pool: address) -> uint256: view def calc_token_amount( _amounts: DynArray[uint256, MAX_COINS], _is_deposit: bool, _pool: address ) -> uint256: view interface StableSwap2: def add_liquidity(amounts: uint256[2], min_mint_amount: uint256): nonpayable interface StableSwap3: def add_liquidity(amounts: uint256[3], min_mint_amount: uint256): nonpayable interface StableSwapNG: def add_liquidity( amounts: DynArray[uint256, MAX_COINS], min_mint_amount: uint256 ) -> uint256: nonpayable interface StableSwap: def remove_liquidity_one_coin(_token_amount: uint256, i: int128, min_amount: uint256): nonpayable def exchange(i: int128, j: int128, dx: uint256, min_dy: uint256): nonpayable def get_virtual_price() -> uint256: view interface Math: def get_y( i: int128, j: int128, x: uint256, xp: DynArray[uint256, MAX_COINS], _amp: uint256, _D: uint256, _n_coins: uint256 ) -> uint256: view def get_y_D( A: uint256, i: int128, xp: DynArray[uint256, MAX_COINS], D: uint256, _n_coins: uint256 ) -> uint256: view def get_D( _xp: DynArray[uint256, MAX_COINS], _amp: uint256, _n_coins: uint256 ) -> uint256: view def exp(x: int256) -> uint256: view # --------------------------------- Events ----------------------------------- event Transfer: sender: indexed(address) receiver: indexed(address) value: uint256 event Approval: owner: indexed(address) spender: indexed(address) value: uint256 event TokenExchange: buyer: indexed(address) sold_id: int128 tokens_sold: uint256 bought_id: int128 tokens_bought: uint256 event TokenExchangeUnderlying: buyer: indexed(address) sold_id: int128 tokens_sold: uint256 bought_id: int128 tokens_bought: uint256 event AddLiquidity: provider: indexed(address) token_amounts: DynArray[uint256, MAX_COINS] fees: DynArray[uint256, MAX_COINS] invariant: uint256 token_supply: uint256 event RemoveLiquidity: provider: indexed(address) token_amounts: DynArray[uint256, MAX_COINS] fees: DynArray[uint256, MAX_COINS] token_supply: uint256 event RemoveLiquidityOne: provider: indexed(address) token_id: int128 token_amount: uint256 coin_amount: uint256 token_supply: uint256 event RemoveLiquidityImbalance: provider: indexed(address) token_amounts: DynArray[uint256, MAX_COINS] fees: DynArray[uint256, MAX_COINS] invariant: uint256 token_supply: uint256 event RampA: old_A: uint256 new_A: uint256 initial_time: uint256 future_time: uint256 event StopRampA: A: uint256 t: uint256 event ApplyNewFee: fee: uint256 offpeg_fee_multiplier: uint256 event SetNewMATime: ma_exp_time: uint256 D_ma_time: uint256 MAX_COINS: constant(uint256) = 8 # max coins is 8 in the factory MAX_COINS_128: constant(int128) = 8 MAX_METAPOOL_COIN_INDEX: constant(int128) = 1 # ---------------------------- Pool Variables -------------------------------- N_COINS: public(constant(uint256)) = 2 N_COINS_128: constant(int128) = 2 PRECISION: constant(uint256) = 10 ** 18 BASE_POOL: public(immutable(address)) BASE_POOL_IS_NG: immutable(bool) BASE_N_COINS: public(immutable(uint256)) BASE_COINS: public(immutable(DynArray[address, MAX_COINS])) math: immutable(Math) factory: immutable(Factory) coins: public(immutable(DynArray[address, MAX_COINS])) asset_type: immutable(uint8) pool_contains_rebasing_tokens: immutable(bool) stored_balances: uint256[N_COINS] # Fee specific vars FEE_DENOMINATOR: constant(uint256) = 10 ** 10 fee: public(uint256) # fee * 1e10 offpeg_fee_multiplier: public(uint256) # * 1e10 admin_fee: public(constant(uint256)) = 5000000000 MAX_FEE: constant(uint256) = 5 * 10 ** 9 # ---------------------- Pool Amplification Parameters ----------------------- A_PRECISION: constant(uint256) = 100 MAX_A: constant(uint256) = 10 ** 6 MAX_A_CHANGE: constant(uint256) = 10 initial_A: public(uint256) future_A: public(uint256) initial_A_time: public(uint256) future_A_time: public(uint256) # ---------------------------- Admin Variables ------------------------------- MIN_RAMP_TIME: constant(uint256) = 86400 admin_balances: public(DynArray[uint256, MAX_COINS]) # ----------------------- Oracle Specific vars ------------------------------- rate_multiplier: immutable(uint256) # [bytes4 method_id][bytes8 <empty>][bytes20 oracle] rate_oracle: immutable(uint256) # this is the rate oracle for the token at 0th index # For ERC4626 tokens, we need: call_amount: immutable(uint256) scale_factor: immutable(uint256) last_prices_packed: uint256 # packing: last_price, ma_price last_D_packed: uint256 # packing: last_D, ma_D ma_exp_time: public(uint256) D_ma_time: public(uint256) ma_last_time: public(uint256) # packing: ma_last_time_p, ma_last_time_D # shift(2**32 - 1, 224) ORACLE_BIT_MASK: constant(uint256) = (2**32 - 1) * 256**28 # --------------------------- ERC20 Specific Vars ---------------------------- name: public(immutable(String[64])) symbol: public(immutable(String[32])) decimals: public(constant(uint8)) = 18 version: public(constant(String[8])) = "v7.0.0" balanceOf: public(HashMap[address, uint256]) allowance: public(HashMap[address, HashMap[address, uint256]]) total_supply: uint256 nonces: public(HashMap[address, uint256]) # keccak256("isValidSignature(bytes32,bytes)")[:4] << 224 ERC1271_MAGIC_VAL: constant(bytes32) = 0x1626ba7e00000000000000000000000000000000000000000000000000000000 EIP712_TYPEHASH: constant(bytes32) = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)") EIP2612_TYPEHASH: constant(bytes32) = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)") VERSION_HASH: constant(bytes32) = keccak256(version) NAME_HASH: immutable(bytes32) CACHED_CHAIN_ID: immutable(uint256) salt: public(immutable(bytes32)) CACHED_DOMAIN_SEPARATOR: immutable(bytes32) # ------------------------------ AMM Setup ----------------------------------- @external def __init__( _name: String[32], _symbol: String[10], _A: uint256, _fee: uint256, _offpeg_fee_multiplier: uint256, _ma_exp_time: uint256, _math_implementation: address, _base_pool: address, _coins: DynArray[address, MAX_COINS], _base_coins: DynArray[address, MAX_COINS], _rate_multipliers: DynArray[uint256, MAX_COINS], _asset_types: DynArray[uint8, MAX_COINS], _method_ids: DynArray[bytes4, MAX_COINS], _oracles: DynArray[address, MAX_COINS], ): """ @notice Initialize the pool contract @param _name Name of the new plain pool. @param _symbol Symbol for the new plain pool. @param _A Amplification co-efficient - a lower value here means less tolerance for imbalance within the pool's assets. Suggested values include: * Uncollateralized algorithmic stablecoins: 5-10 * Non-redeemable, collateralized assets: 100 * Redeemable assets: 200-400 @param _fee Trade fee, given as an integer with 1e10 precision. The the maximum is 1% (100000000). 50% of the fee is distributed to veCRV holders. @param _offpeg_fee_multiplier A multiplier that determines how much to increase Fees by when assets in the AMM depeg. Example: 20000000000 @param _ma_exp_time Averaging window of oracle. Set as time_in_seconds / ln(2) Example: for 10 minute EMA, _ma_exp_time is 600 / ln(2) ~= 866 @param _math_implementation Contract containing Math methods @param _base_pool The underlying AMM of the LP token _coins[0] is paired against @param _coins List of addresses of the coins being used in the pool. For metapool this is the coin (say LUSD) vs (say) 3crv as: [LUSD, 3CRV]. Length is always 2. @param _base_coins coins in the underlying base pool. @param _rate_multipliers Rate multipliers of the individual coins. For Metapools it is: [10 ** (36 - _coins[0].decimals()), 10 ** 18]. @param _asset_types Array of uint8 representing tokens in pool @param _method_ids Array of first four bytes of the Keccak-256 hash of the function signatures of the oracle addresses that gives rate oracles. Calculated as: keccak(text=event_signature.replace(" ", ""))[:4] @param _oracles Array of rate oracle addresses. """ # The following reverts if BASE_POOL is an NG implementaion. BASE_POOL_IS_NG = raw_call(_base_pool, method_id("D_ma_time()"), revert_on_failure=False) if not BASE_POOL_IS_NG: assert len(_base_coins) <= 3 # dev: implementation does not support old gen base pool with more than 3 coins math = Math(_math_implementation) BASE_POOL = _base_pool BASE_COINS = _base_coins BASE_N_COINS = len(_base_coins) coins = _coins # <---------------- coins[1] is always base pool LP token. asset_type = _asset_types[0] pool_contains_rebasing_tokens = asset_type == 2 rate_multiplier = _rate_multipliers[0] for i in range(MAX_COINS): if i < BASE_N_COINS: # Approval needed for add_liquidity operation on base pool in # _exchange_underlying: assert ERC20(_base_coins[i]).approve( BASE_POOL, max_value(uint256), default_return_value = True ) # For ERC4626 tokens: if asset_type == 3: # In Vyper 0.3.10, if immutables are not set, because of an if-statement, # it is by default set to 0; this is fine in the case of these two # immutables, since they are only used if asset_types[0] == 3. call_amount = 10**convert(ERC20Detailed(_coins[0]).decimals(), uint256) scale_factor = 10**(18 - convert(ERC20Detailed(ERC4626(_coins[0]).asset()).decimals(), uint256)) # ----------------- Parameters independent of pool type ------------------ factory = Factory(msg.sender) A: uint256 = unsafe_mul(_A, A_PRECISION) self.initial_A = A self.future_A = A self.fee = _fee self.offpeg_fee_multiplier = _offpeg_fee_multiplier assert _ma_exp_time != 0 self.ma_exp_time = _ma_exp_time self.D_ma_time = 62324 # <--------- 12 hours default on contract start. self.ma_last_time = self.pack_2(block.timestamp, block.timestamp) self.last_prices_packed = self.pack_2(10**18, 10**18) self.admin_balances = [0, 0] self.stored_balances = [0, 0] rate_oracle = convert(_method_ids[0], uint256) * 2**224 | convert(_oracles[0], uint256) # --------------------------- ERC20 stuff ---------------------------- name = _name symbol = _symbol # EIP712 related params ----------------- NAME_HASH = keccak256(name) salt = block.prevhash CACHED_CHAIN_ID = chain.id CACHED_DOMAIN_SEPARATOR = keccak256( _abi_encode( EIP712_TYPEHASH, NAME_HASH, VERSION_HASH, chain.id, self, salt, ) ) # ------------------------ Fire a transfer event ------------------------- log Transfer(empty(address), msg.sender, 0) # ------------------ Token transfers in and out of the AMM ------------------- @internal def _transfer_in( coin_metapool_idx: int128, coin_basepool_idx: int128, dx: uint256, sender: address, expect_optimistic_transfer: bool, is_base_pool_swap: bool = False, ) -> uint256: """ @notice Contains all logic to handle ERC20 token transfers. @param coin_metapool_idx metapool index of input coin @param coin_basepool_idx basepool index of input coin @param dx amount of `_coin` to transfer into the pool. @param sender address to transfer `_coin` from. @param expect_optimistic_transfer True if contract expects an optimistic coin transfer @param is_base_pool_swap Default is set to False. @return amount of coins received """ _input_coin: ERC20 = ERC20(coins[coin_metapool_idx]) _input_coin_is_in_base_pool: bool = False # Check if _transfer_in is being called by _exchange_underlying: if coin_basepool_idx >= 0 and coin_metapool_idx == 1: _input_coin = ERC20(BASE_COINS[coin_basepool_idx]) _input_coin_is_in_base_pool = True _dx: uint256 = _input_coin.balanceOf(self) # ------------------------- Handle Transfers ----------------------------- if expect_optimistic_transfer: if not _input_coin_is_in_base_pool: _dx = _dx - self.stored_balances[coin_metapool_idx] assert _dx >= dx # dev: pool did not receive tokens for swap else: assert dx > 0 # dev : do not transferFrom 0 tokens into the pool assert _input_coin.transferFrom( sender, self, dx, default_return_value=True ) _dx = _input_coin.balanceOf(self) - _dx # ------------ Check if liquidity needs to be added somewhere ------------ if _input_coin_is_in_base_pool: if is_base_pool_swap: return _dx # <----- _exchange_underlying: all input goes to swap. # So, we will not increment self.stored_balances for metapool_idx. # Swap involves base <> meta pool interaction. Add incoming base pool # token to the base pool, mint _dx base pool LP token (idx 1) and add # that to self.stored_balances and return that instead. _dx = self._meta_add_liquidity(_dx, coin_basepool_idx) # ----------------------- Update Stored Balances ------------------------- self.stored_balances[coin_metapool_idx] += _dx return _dx @internal def _transfer_out( _coin_idx: int128, _amount: uint256, receiver: address ): """ @notice Transfer a single token from the pool to receiver. @dev This function is called by `remove_liquidity` and `remove_liquidity_one_coin`, `_exchange`, `_withdraw_admin_fees` and `remove_liquidity_imbalance` methods. @param _coin_idx Index of the token to transfer out @param _amount Amount of token to transfer out @param receiver Address to send the tokens to """ assert receiver != empty(address) # dev: do not send tokens to zero_address if not pool_contains_rebasing_tokens: # we need not cache balanceOf pool before swap out self.stored_balances[_coin_idx] -= _amount assert ERC20(coins[_coin_idx]).transfer( receiver, _amount, default_return_value=True ) else: # cache balances pre and post to account for fee on transfers etc. coin_balance: uint256 = ERC20(coins[_coin_idx]).balanceOf(self) assert ERC20(coins[_coin_idx]).transfer( receiver, _amount, default_return_value=True ) self.stored_balances[_coin_idx] = coin_balance - _amount # -------------------------- AMM Special Methods ----------------------------- @view @internal def _stored_rates() -> uint256[N_COINS]: """ @notice Gets rate multipliers for each coin. @dev If the coin has a rate oracle that has been properly initialised, this method queries that rate by static-calling an external contract. """ rates: uint256[N_COINS] = [rate_multiplier, StableSwap(BASE_POOL).get_virtual_price()] if asset_type == 1 and not rate_oracle == 0: # NOTE: fetched_rate is assumed to be 10**18 precision oracle_response: Bytes[32] = raw_call( convert(rate_oracle % 2**160, address), _abi_encode(rate_oracle & ORACLE_BIT_MASK), max_outsize=32, is_static_call=True, ) assert len(oracle_response) == 32 fetched_rate: uint256 = convert(oracle_response, uint256) # rates[0] * fetched_rate / PRECISION rates[0] = unsafe_div(rates[0] * fetched_rate, PRECISION) elif asset_type == 3: # ERC4626 # rates[0] * fetched_rate / PRECISION rates[0] = unsafe_div( rates[0] * ERC4626(coins[0]).convertToAssets(call_amount) * scale_factor, PRECISION ) # 1e18 precision return rates @view @internal def _balances() -> uint256[N_COINS]: """ @notice Calculates the pool's balances _excluding_ the admin's balances. @dev If the pool contains rebasing tokens, this method ensures LPs keep all rebases and admin only claims swap fees. This also means that, since admin's balances are stored in an array and not inferred from read balances, the fees in the rebasing token that the admin collects is immune to slashing events. """ result: uint256[N_COINS] = empty(uint256[N_COINS]) admin_balances: DynArray[uint256, MAX_COINS] = self.admin_balances for i in range(N_COINS_128): if pool_contains_rebasing_tokens: # Read balances by gulping to account for rebases result[i] = ERC20(coins[i]).balanceOf(self) - admin_balances[i] else: # Use cached balances result[i] = self.stored_balances[i] - admin_balances[i] return result # -------------------------- AMM Main Functions ------------------------------ @external @nonreentrant('lock') def exchange( i: int128, j: int128, _dx: uint256, _min_dy: uint256, _receiver: address = msg.sender, ) -> uint256: """ @notice Perform an exchange between two coins @dev Index values can be found via the `coins` public getter method @param i Index value for the coin to send @param j Index value of the coin to receive @param _dx Amount of `i` being exchanged @param _min_dy Minimum amount of `j` to receive @param _receiver Address that receives `j` @return Actual amount of `j` received """ return self._exchange( msg.sender, i, j, _dx, _min_dy, _receiver, False ) @external @nonreentrant('lock') def exchange_received( i: int128, j: int128, _dx: uint256, _min_dy: uint256, _receiver: address = msg.sender, ) -> uint256: """ @notice Perform an exchange between two coins without transferring token in @dev The contract swaps tokens based on a change in balance of coin[i]. The dx = ERC20(coin[i]).balanceOf(self) - self.stored_balances[i]. Users of this method are dex aggregators, arbitrageurs, or other users who do not wish to grant approvals to the contract: they would instead send tokens directly to the contract and call `exchange_received`. Note: This is disabled if pool contains rebasing tokens. @param i Index value for the coin to send @param j Index value of the coin to receive @param _dx Amount of `i` being exchanged @param _min_dy Minimum amount of `j` to receive @param _receiver Address that receives `j` @return Actual amount of `j` received """ assert not pool_contains_rebasing_tokens # dev: exchange_received not supported if pool contains rebasing tokens return self._exchange( msg.sender, i, j, _dx, _min_dy, _receiver, True, # <--------------------------------------- swap optimistically. ) @external @nonreentrant('lock') def exchange_underlying( i: int128, j: int128, _dx: uint256, _min_dy: uint256, _receiver: address = msg.sender, ) -> uint256: """ @notice Perform an exchange between two underlying coins @param i Index value for the underlying coin to send @param j Index value of the underlying coin to receive @param _dx Amount of `i` being exchanged @param _min_dy Minimum amount of `j` to receive @param _receiver Address that receives `j` @return Actual amount of `j` received """ assert _receiver != empty(address) # dev: do not send tokens to zero_address rates: uint256[N_COINS] = self._stored_rates() old_balances: uint256[N_COINS] = self._balances() xp: uint256[N_COINS] = self._xp_mem(rates, old_balances) dy: uint256 = 0 base_i: int128 = 0 base_j: int128 = 0 meta_i: int128 = 0 meta_j: int128 = 0 x: uint256 = 0 output_coin: address = empty(address) # ------------------------ Determine coin indices ------------------------ # Get input coin indices: if i > 0: base_i = i - MAX_METAPOOL_COIN_INDEX meta_i = 1 # Get output coin and indices: if j == 0: output_coin = coins[0] else: base_j = j - MAX_METAPOOL_COIN_INDEX meta_j = 1 output_coin = BASE_COINS[base_j] # --------------------------- Do Transfer in ----------------------------- # If incoming coin is supposed to go to the base pool, the _transfer_in # method will add_liquidity in the base pool and return dx_w_fee LP tokens dx_w_fee: uint256 = self._transfer_in( meta_i, base_i, _dx, msg.sender, False, (i > 0 and j > 0), # <--- if True: do not add liquidity to base pool. ) # ------------------------------- Exchange ------------------------------- if i == 0 or j == 0: # meta swap x = xp[meta_i] + unsafe_div(dx_w_fee * rates[meta_i], PRECISION) dy = self.__exchange(x, xp, rates, meta_i, meta_j) # Adjust stored balances of meta-level tokens: self.stored_balances[meta_j] -= dy # Withdraw from the base pool if needed if j > 0: out_amount: uint256 = ERC20(output_coin).balanceOf(self) StableSwap(BASE_POOL).remove_liquidity_one_coin(dy, base_j, 0) dy = ERC20(output_coin).balanceOf(self) - out_amount assert dy >= _min_dy else: # base pool swap (user should swap at base pool for better gas) dy = ERC20(output_coin).balanceOf(self) StableSwap(BASE_POOL).exchange(base_i, base_j, dx_w_fee, _min_dy) dy = ERC20(output_coin).balanceOf(self) - dy # --------------------------- Do Transfer out ---------------------------- assert ERC20(output_coin).transfer(_receiver, dy, default_return_value=True) # ------------------------------------------------------------------------ log TokenExchangeUnderlying(msg.sender, i, _dx, j, dy) return dy @external @nonreentrant('lock') def add_liquidity( _amounts: uint256[N_COINS], _min_mint_amount: uint256, _receiver: address = msg.sender ) -> uint256: """ @notice Deposit coins into the pool @param _amounts List of amounts of coins to deposit @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit @param _receiver Address that owns the minted LP tokens @return Amount of LP tokens received by depositing """ assert _receiver != empty(address) # dev: do not send LP tokens to zero_address amp: uint256 = self._A() old_balances: uint256[N_COINS] = self._balances() rates: uint256[N_COINS] = self._stored_rates() # Initial invariant D0: uint256 = self.get_D_mem(rates, old_balances, amp) total_supply: uint256 = self.total_supply new_balances: uint256[N_COINS] = old_balances # -------------------------- Do Transfers In ----------------------------- for i in range(N_COINS_128): if _amounts[i] > 0: new_balances[i] += self._transfer_in( i, -1, # <--- we're not handling underlying coins here _amounts[i], msg.sender, False, # expect_optimistic_transfer ) else: assert total_supply != 0 # dev: initial deposit requires all coins # ------------------------------------------------------------------------ # Invariant after change D1: uint256 = self.get_D_mem(rates, new_balances, amp) assert D1 > D0 # We need to recalculate the invariant accounting for fees # to calculate fair user's share fees: uint256[N_COINS] = empty(uint256[N_COINS]) mint_amount: uint256 = 0 if total_supply > 0: ideal_balance: uint256 = 0 difference: uint256 = 0 new_balance: uint256 = 0 ys: uint256 = unsafe_div(D0 + D1, N_COINS) xs: uint256 = 0 _dynamic_fee_i: uint256 = 0 # Only account for fees if we are not the first to deposit # base_fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1)) # unsafe math is safu here: base_fee: uint256 = unsafe_div(unsafe_mul(self.fee, N_COINS), 4) for i in range(N_COINS_128): ideal_balance = D1 * old_balances[i] / D0 new_balance = new_balances[i] # unsafe math is safu here: if ideal_balance > new_balance: difference = unsafe_sub(ideal_balance, new_balance) else: difference = unsafe_sub(new_balance, ideal_balance) # fee[i] = _dynamic_fee(i, j) * difference / FEE_DENOMINATOR xs = unsafe_div(rates[i] * (old_balances[i] + new_balance), PRECISION) _dynamic_fee_i = self._dynamic_fee(xs, ys, base_fee) fees[i] = unsafe_div(_dynamic_fee_i * difference, FEE_DENOMINATOR) # fees[i] * admin_fee / FEE_DENOMINATOR self.admin_balances[i] += unsafe_div(fees[i] * admin_fee, FEE_DENOMINATOR) new_balances[i] -= fees[i] xp: uint256[N_COINS] = self._xp_mem(rates, new_balances) D1 = math.get_D([xp[0], xp[1]], amp, N_COINS) # <------ Reuse D1 for new D value. # we do unsafe div here because we already did several safedivs with D0 mint_amount = unsafe_div(total_supply * (D1 - D0), D0) self.upkeep_oracles(xp, amp, D1) else: mint_amount = D1 # Take the dust if there was any # (re)instantiate D oracle if totalSupply is zero. self.last_D_packed = self.pack_2(D1, D1) # Update D ma time: ma_last_time_unpacked: uint256[2] = self.unpack_2(self.ma_last_time) if ma_last_time_unpacked[1] < block.timestamp: ma_last_time_unpacked[1] = block.timestamp self.ma_last_time = self.pack_2(ma_last_time_unpacked[0], ma_last_time_unpacked[1]) assert mint_amount >= _min_mint_amount, "Slippage screwed you" # Mint pool tokens total_supply += mint_amount user_lp_token_bal: uint256 = self.balanceOf[_receiver] # here we can increase balance using unsafe add because # user balance will always be <= total_supply. so if total_supply # safeadd works, this can be safely unsafe: self.balanceOf[_receiver] = unsafe_add(user_lp_token_bal, mint_amount) self.total_supply = total_supply log Transfer(empty(address), _receiver, mint_amount) log AddLiquidity( msg.sender, [_amounts[0], _amounts[1]], [fees[0], fees[1]], D1, total_supply ) return mint_amount @external @nonreentrant('lock') def remove_liquidity_one_coin( _burn_amount: uint256, i: int128, _min_received: uint256, _receiver: address = msg.sender, ) -> uint256: """ @notice Withdraw a single coin from the pool @param _burn_amount Amount of LP tokens to burn in the withdrawal @param i Index value of the coin to withdraw @param _min_received Minimum amount of coin to receive @param _receiver Address that receives the withdrawn coins @return Amount of coin received """ assert _burn_amount > 0 # dev: do not remove 0 LP tokens dy: uint256 = 0 fee: uint256 = 0 xp: uint256[N_COINS] = empty(uint256[N_COINS]) amp: uint256 = empty(uint256) D: uint256 = empty(uint256) dy, fee, xp, amp, D = self._calc_withdraw_one_coin(_burn_amount, i) assert dy >= _min_received, "Not enough coins removed" # fee * admin_fee / FEE_DENOMINATOR self.admin_balances[i] += unsafe_div(fee * admin_fee, FEE_DENOMINATOR) self._burnFrom(msg.sender, _burn_amount) self._transfer_out(i, dy, _receiver) log RemoveLiquidityOne(msg.sender, i, _burn_amount, dy, self.total_supply) self.upkeep_oracles(xp, amp, D) return dy @external @nonreentrant('lock') def remove_liquidity_imbalance( _amounts: uint256[N_COINS], _max_burn_amount: uint256, _receiver: address = msg.sender ) -> uint256: """ @notice Withdraw coins from the pool in an imbalanced amount @param _amounts List of amounts of underlying coins to withdraw @param _max_burn_amount Maximum amount of LP token to burn in the withdrawal @param _receiver Address that receives the withdrawn coins @return Actual amount of the LP token burned in the withdrawal """ amp: uint256 = self._A() rates: uint256[N_COINS] = self._stored_rates() old_balances: uint256[N_COINS] = self._balances() D0: uint256 = self.get_D_mem(rates, old_balances, amp) new_balances: uint256[N_COINS] = old_balances for i in range(N_COINS_128): if _amounts[i] != 0: new_balances[i] -= _amounts[i] self._transfer_out(i, _amounts[i], _receiver) D1: uint256 = self.get_D_mem(rates, new_balances, amp) # base_fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1)) base_fee: uint256 = unsafe_div(unsafe_mul(self.fee, N_COINS), 4) # ys: uint256 = (D0 + D1) / N_COINS ys: uint256 = unsafe_div(D0 + D1, N_COINS) fees: uint256[N_COINS] = empty(uint256[N_COINS]) dynamic_fee: uint256 = 0 xs: uint256 = 0 ideal_balance: uint256 = 0 difference: uint256 = 0 new_balance: uint256 = 0 for i in range(N_COINS_128): ideal_balance = D1 * old_balances[i] / D0 new_balance = new_balances[i] if ideal_balance > new_balance: difference = unsafe_sub(ideal_balance, new_balance) else: difference = unsafe_sub(new_balance, ideal_balance) # base_fee * difference / FEE_DENOMINATOR xs = unsafe_div(rates[i] * (old_balances[i] + new_balance), PRECISION) dynamic_fee = self._dynamic_fee(xs, ys, base_fee) fees[i] = unsafe_div(dynamic_fee * difference, FEE_DENOMINATOR) # fees[i] * admin_fee / FEE_DENOMINATOR self.admin_balances[i] += unsafe_div(fees[i] * admin_fee, FEE_DENOMINATOR) new_balances[i] -= fees[i] D1 = self.get_D_mem(rates, new_balances, amp) # dev: reuse D1 for new D. self.upkeep_oracles(self._xp_mem(rates, new_balances), amp, D1) total_supply: uint256 = self.total_supply # here we can do unsafe div by D0 because we did several safedivs: # burn_amount: uint256 = ((D0 - D1) * total_supply / D0) + 1 burn_amount: uint256 = unsafe_div((D0 - D1) * total_supply, D0) + 1 assert burn_amount > 1 # dev: zero tokens burned assert burn_amount <= _max_burn_amount, "Slippage screwed you" self._burnFrom(msg.sender, burn_amount) log RemoveLiquidityImbalance( msg.sender, [_amounts[0], _amounts[1]], [fees[0], fees[1]], D1, total_supply - burn_amount ) return burn_amount @external @nonreentrant('lock') def remove_liquidity( _burn_amount: uint256, _min_amounts: uint256[N_COINS], _receiver: address = msg.sender, _claim_admin_fees: bool = True, ) -> uint256[N_COINS]: """ @notice Withdraw coins from the pool @dev Withdrawal amounts are based on current deposit ratios @param _burn_amount Quantity of LP tokens to burn in the withdrawal @param _min_amounts Minimum amounts of underlying coins to receive @param _receiver Address that receives the withdrawn coins @return List of amounts of coins that were withdrawn """ total_supply: uint256 = self.total_supply assert _burn_amount > 0 # dev: invalid _burn_amount amounts: uint256[N_COINS] = empty(uint256[N_COINS]) balances: uint256[N_COINS] = self._balances() value: uint256 = 0 for i in range(N_COINS_128): value = unsafe_div(balances[i] * _burn_amount, total_supply) assert value >= _min_amounts[i], "Withdrawal resulted in fewer coins than expected" amounts[i] = value self._transfer_out(i, value, _receiver) self._burnFrom(msg.sender, _burn_amount) # dev: insufficient funds # --------------------------- Upkeep D_oracle ---------------------------- ma_last_time_unpacked: uint256[2] = self.unpack_2(self.ma_last_time) last_D_packed_current: uint256 = self.last_D_packed old_D: uint256 = last_D_packed_current & (2**128 - 1) self.last_D_packed = self.pack_2( old_D - unsafe_div(old_D * _burn_amount, total_supply), # new_D = proportionally reduce D. self._calc_moving_average( last_D_packed_current, self.D_ma_time, ma_last_time_unpacked[1] ) ) if ma_last_time_unpacked[1] < block.timestamp: ma_last_time_unpacked[1] = block.timestamp self.ma_last_time = self.pack_2(ma_last_time_unpacked[0], ma_last_time_unpacked[1]) # ------------------------------- Log event ------------------------------ log RemoveLiquidity( msg.sender, [amounts[0], amounts[1]], empty(DynArray[uint256, MAX_COINS]), unsafe_sub(total_supply, _burn_amount) ) # ------- Withdraw admin fees if _claim_admin_fees is set to True -------- if _claim_admin_fees: self._withdraw_admin_fees() return [amounts[0], amounts[1]] @external def withdraw_admin_fees(): """ @notice Claim admin fees. Callable by anyone. """ self._withdraw_admin_fees() # ------------------------ AMM Internal Functions ---------------------------- @view @internal def _dynamic_fee(xpi: uint256, xpj: uint256, _fee: uint256) -> uint256: _offpeg_fee_multiplier: uint256 = self.offpeg_fee_multiplier # to remove dynamic fee: just set _offpeg_fee_multiplier less than FEE_DENOMINATOR if _offpeg_fee_multiplier <= FEE_DENOMINATOR: return _fee xps2: uint256 = (xpi + xpj) ** 2 return unsafe_div( unsafe_mul(_offpeg_fee_multiplier, _fee), unsafe_add( unsafe_sub(_offpeg_fee_multiplier, FEE_DENOMINATOR) * 4 * xpi * xpj / xps2, FEE_DENOMINATOR ) ) @internal def __exchange( x: uint256, _xp: uint256[N_COINS], rates: uint256[N_COINS], i: int128, j: int128, ) -> uint256: amp: uint256 = self._A() D: uint256 = math.get_D([_xp[0], _xp[1]], amp, N_COINS) y: uint256 = math.get_y(i, j, x, [_xp[0], _xp[1]], amp, D, N_COINS) dy: uint256 = _xp[j] - y - 1 # -1 just in case there were some rounding errors dy_fee: uint256 = unsafe_div( dy * self._dynamic_fee( unsafe_div(_xp[i] + x, 2), unsafe_div(_xp[j] + y, 2), self.fee ), FEE_DENOMINATOR ) # Convert all to real units dy = (dy - dy_fee) * PRECISION / rates[j] # admin_fee = dy_fee * admin_fee / FEE_DENOMINATOR self.admin_balances[j] += unsafe_div( unsafe_div(dy_fee * admin_fee, FEE_DENOMINATOR) * PRECISION, rates[j] # we can do unsafediv here because we did safediv before ) # Calculate and store state prices: xp: uint256[N_COINS] = _xp xp[i] = x xp[j] = y # D is not changed because we did not apply a fee self.upkeep_oracles(xp, amp, D) return dy @internal def _exchange( sender: address, i: int128, j: int128, _dx: uint256, _min_dy: uint256, receiver: address, expect_optimistic_transfer: bool ) -> uint256: assert i != j # dev: coin index out of range assert _dx > 0 # dev: do not exchange 0 coins rates: uint256[N_COINS] = self._stored_rates() old_balances: uint256[N_COINS] = self._balances() xp: uint256[N_COINS] = self._xp_mem(rates, old_balances) # --------------------------- Do Transfer in ----------------------------- # `dx` is whatever the pool received after ERC20 transfer: dx: uint256 = self._transfer_in( i, -1, _dx, sender, expect_optimistic_transfer ) # ------------------------------- Exchange ------------------------------- # xp[i] + dx * rates[i] / PRECISION x: uint256 = xp[i] + unsafe_div(dx * rates[i], PRECISION) dy: uint256 = self.__exchange(x, xp, rates, i, j) assert dy >= _min_dy, "Exchange resulted in fewer coins than expected" # --------------------------- Do Transfer out ---------------------------- self._transfer_out(j, dy, receiver) # ------------------------------------------------------------------------ log TokenExchange(msg.sender, i, dx, j, dy) return dy @internal def _meta_add_liquidity(dx: uint256, base_i: int128) -> uint256: if BASE_POOL_IS_NG: base_inputs: DynArray[uint256, MAX_COINS] = empty(DynArray[uint256, MAX_COINS]) for i in range(BASE_N_COINS, bound=MAX_COINS): if i == convert(base_i, uint256): base_inputs.append(dx) else: base_inputs.append(0) return StableSwapNG(BASE_POOL).add_liquidity(base_inputs, 0) coin_i: address = coins[MAX_METAPOOL_COIN_INDEX] x: uint256 = ERC20(coin_i).balanceOf(self) if BASE_N_COINS == 2: base_inputs: uint256[2] = empty(uint256[2]) base_inputs[base_i] = dx StableSwap2(BASE_POOL).add_liquidity(base_inputs, 0) if BASE_N_COINS == 3: base_inputs: uint256[3] = empty(uint256[3]) base_inputs[base_i] = dx StableSwap3(BASE_POOL).add_liquidity(base_inputs, 0) return ERC20(coin_i).balanceOf(self) - x @internal def _withdraw_admin_fees(): fee_receiver: address = factory.fee_receiver() if fee_receiver == empty(address): return # Do nothing. admin_balances: DynArray[uint256, MAX_COINS] = self.admin_balances for i in range(N_COINS_128): if admin_balances[i] > 0: self._transfer_out(i, admin_balances[i], fee_receiver) self.admin_balances = [0, 0] # --------------------------- AMM Math Functions ----------------------------- @view @internal def _A() -> uint256: """ Handle ramping A up or down """ t1: uint256 = self.future_A_time A1: uint256 = self.future_A if block.timestamp < t1: A0: uint256 = self.initial_A t0: uint256 = self.initial_A_time # Expressions in uint256 cannot have negative numbers, thus "if" if A1 > A0: return A0 + unsafe_sub(A1, A0) * (block.timestamp - t0) / (t1 - t0) else: return A0 - unsafe_sub(A0, A1) * (block.timestamp - t0) / (t1 - t0) else: # when t1 == 0 or block.timestamp >= t1 return A1 @pure @internal def _xp_mem(_rates: uint256[N_COINS], _balances: uint256[N_COINS]) -> uint256[N_COINS]: result: uint256[N_COINS] = empty(uint256[N_COINS]) for i in range(N_COINS_128): # _rates[i] * _balances[i] / PRECISION result[i] = unsafe_div(_rates[i] * _balances[i], PRECISION) return result @view @internal def get_D_mem( _rates: uint256[N_COINS], _balances: uint256[N_COINS], _amp: uint256 ) -> uint256: xp: uint256[N_COINS] = self._xp_mem(_rates, _balances) return math.get_D([xp[0], xp[1]], _amp, N_COINS) @view @internal def _calc_withdraw_one_coin( _burn_amount: uint256, i: int128 ) -> ( uint256, uint256, uint256[N_COINS], uint256, uint256 ): # First, need to: # * Get current D # * Solve Eqn against y_i for D - _token_amount # get pool state amp: uint256 = self._A() rates: uint256[N_COINS] = self._stored_rates() xp: uint256[N_COINS] = self._xp_mem(rates, self._balances()) D0: uint256 = math.get_D([xp[0], xp[1]], amp, N_COINS) total_supply: uint256 = self.total_supply D1: uint256 = D0 - _burn_amount * D0 / total_supply new_y: uint256 = math.get_y_D(amp, i, [xp[0], xp[1]], D1, N_COINS) base_fee: uint256 = unsafe_div(unsafe_mul(self.fee, N_COINS), 4) xp_reduced: uint256[N_COINS] = xp # ys: uint256 = (D0 + D1) / (2 * N_COINS) ys: uint256 = unsafe_div((D0 + D1), 4) # base_fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1)) dx_expected: uint256 = 0 xp_j: uint256 = 0 xavg: uint256 = 0 dynamic_fee: uint256 = 0 for j in range(N_COINS_128): dx_expected = 0 xp_j = xp[j] if j == i: dx_expected = xp_j * D1 / D0 - new_y xavg = unsafe_div(xp_j + new_y, 2) else: dx_expected = xp_j - xp_j * D1 / D0 xavg = xp_j # xp_j - dynamic_fee * dx_expected / FEE_DENOMINATOR dynamic_fee = self._dynamic_fee(xavg, ys, base_fee) xp_reduced[j] = xp_j - unsafe_div(dynamic_fee * dx_expected, FEE_DENOMINATOR) dy: uint256 = xp_reduced[i] - math.get_y_D(amp, i, [xp_reduced[0], xp_reduced[1]], D1, N_COINS) dy_0: uint256 = (xp[i] - new_y) * PRECISION / rates[i] # w/o fees dy = unsafe_div((dy - 1) * PRECISION, rates[i]) # Withdraw less to account for rounding errors # calculate state price xp[i] = new_y return dy, dy_0 - dy, xp, amp, D1 # -------------------------- AMM Price Methods ------------------------------- @pure @internal def pack_2(p1: uint256, p2: uint256) -> uint256: assert p1 < 2**128 assert p2 < 2**128 return p1 | (p2 << 128) @pure @internal def unpack_2(packed: uint256) -> uint256[2]: return [packed & (2**128 - 1), packed >> 128] @internal @pure def _get_p( xp: uint256[N_COINS], amp: uint256, D: uint256, ) -> uint256: # dx_0 / dx_1 only, however can have any number of coins in pool ANN: uint256 = unsafe_mul(amp, N_COINS) Dr: uint256 = unsafe_div(D, pow_mod256(N_COINS, N_COINS)) for i in range(N_COINS_128): Dr = Dr * D / xp[i] # ANN * xp[0] / A_PRECISION xp0_A: uint256 = unsafe_div(ANN * xp[0], A_PRECISION) return 10**18 * (xp0_A + unsafe_div(Dr * xp[0], xp[1])) / (xp0_A + Dr) @internal def upkeep_oracles(xp: uint256[N_COINS], amp: uint256, D: uint256): """ @notice Upkeeps price and D oracles. """ ma_last_time_unpacked: uint256[2] = self.unpack_2(self.ma_last_time) last_prices_packed_current: uint256 = self.last_prices_packed last_prices_packed_new: uint256 = last_prices_packed_current spot_price: uint256 = self._get_p(xp, amp, D) # -------------------------- Upkeep price oracle ------------------------- # Metapools are always 2-coin pools, so we care about idx=0 only: if spot_price != 0: # Update packed prices ----------------- last_prices_packed_new = self.pack_2( min(spot_price, 2 * 10**18), # <----- Cap spot value by 2. self._calc_moving_average( last_prices_packed_current, self.ma_exp_time, ma_last_time_unpacked[0], # index 0 is ma_exp_time for prices ) ) self.last_prices_packed = last_prices_packed_new # ---------------------------- Upkeep D oracle --------------------------- self.last_D_packed = self.pack_2( D, self._calc_moving_average( self.last_D_packed, self.D_ma_time, ma_last_time_unpacked[1], # index 1 is ma_exp_time for D ) ) # Housekeeping: Update ma_last_time for p and D oracles ------------------ for i in range(2): if ma_last_time_unpacked[i] < block.timestamp: ma_last_time_unpacked[i] = block.timestamp self.ma_last_time = self.pack_2(ma_last_time_unpacked[0], ma_last_time_unpacked[1]) @internal @view def _calc_moving_average( packed_value: uint256, averaging_window: uint256, ma_last_time: uint256 ) -> uint256: last_spot_value: uint256 = packed_value & (2**128 - 1) last_ema_value: uint256 = (packed_value >> 128) if ma_last_time < block.timestamp: # calculate new_ema_value and return that. alpha: uint256 = math.exp( -convert( unsafe_div(unsafe_mul(unsafe_sub(block.timestamp, ma_last_time), 10**18), averaging_window), int256 ) ) return unsafe_div(last_spot_value * (10**18 - alpha) + last_ema_value * alpha, 10**18) return last_ema_value @view @external def last_price(i: uint256) -> uint256: assert i == 0 # dev: metapools do not have last_price indices greater than 0. return self.last_prices_packed & (2**128 - 1) @view @external def ema_price(i: uint256) -> uint256: assert i == 0 # dev: metapools do not have ema_price indices greater than 0. return (self.last_prices_packed >> 128) @external @view def get_p(i: uint256) -> uint256: """ @notice Returns the AMM State price of token @dev if i = 0, it will return the state price of coin[1]. @param i index of state price (0 for coin[1], 1 for coin[2], ...) @return uint256 The state price quoted by the AMM for coin[i+1] """ assert i == 0 # dev: metapools do not have get_p indices greater than 0. amp: uint256 = self._A() xp: uint256[N_COINS] = self._xp_mem( self._stored_rates(), self._balances() ) D: uint256 = math.get_D([xp[0], xp[1]], amp, N_COINS) return self._get_p(xp, amp, D) @external @view @nonreentrant('lock') def price_oracle(i: uint256) -> uint256: assert i == 0 # dev: metapools do not have price_oracle indices greater than 0. return self._calc_moving_average( self.last_prices_packed, self.ma_exp_time, self.ma_last_time & (2**128 - 1), ) @external @view @nonreentrant('lock') def D_oracle() -> uint256: return self._calc_moving_average( self.last_D_packed, self.D_ma_time, self.ma_last_time >> 128 ) # ---------------------------- ERC20 Utils ----------------------------------- @view @internal def _domain_separator() -> bytes32: if chain.id != CACHED_CHAIN_ID: return keccak256( _abi_encode( EIP712_TYPEHASH, NAME_HASH, VERSION_HASH, chain.id, self, salt, ) ) return CACHED_DOMAIN_SEPARATOR @internal def _transfer(_from: address, _to: address, _value: uint256): # # NOTE: vyper does not allow underflows # # so the following subtraction would revert on insufficient balance self.balanceOf[_from] -= _value self.balanceOf[_to] += _value log Transfer(_from, _to, _value) @internal def _burnFrom(_from: address, _burn_amount: uint256): self.total_supply -= _burn_amount self.balanceOf[_from] -= _burn_amount log Transfer(_from, empty(address), _burn_amount) @external def transfer(_to : address, _value : uint256) -> bool: """ @dev Transfer token for a specified address @param _to The address to transfer to. @param _value The amount to be transferred. """ self._transfer(msg.sender, _to, _value) return True @external def transferFrom(_from : address, _to : address, _value : uint256) -> bool: """ @dev Transfer tokens from one address to another. @param _from address The address which you want to send tokens from @param _to address The address which you want to transfer to @param _value uint256 the amount of tokens to be transferred """ self._transfer(_from, _to, _value) _allowance: uint256 = self.allowance[_from][msg.sender] if _allowance != max_value(uint256): _new_allowance: uint256 = _allowance - _value self.allowance[_from][msg.sender] = _new_allowance log Approval(_from, msg.sender, _new_allowance) return True @external def approve(_spender : address, _value : uint256) -> bool: """ @notice Approve the passed address to transfer the specified amount of tokens on behalf of msg.sender @dev Beware that changing an allowance via this method brings the risk that someone may use both the old and new allowance by unfortunate transaction ordering: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 @param _spender The address which will transfer the funds @param _value The amount of tokens that may be transferred @return bool success """ self.allowance[msg.sender][_spender] = _value log Approval(msg.sender, _spender, _value) return True @external def permit( _owner: address, _spender: address, _value: uint256, _deadline: uint256, _v: uint8, _r: bytes32, _s: bytes32 ) -> bool: """ @notice Approves spender by owner's signature to expend owner's tokens. See https://eips.ethereum.org/EIPS/eip-2612. @dev Inspired by https://github.com/yearn/yearn-vaults/blob/main/contracts/Vault.vy#L753-L793 @dev Supports smart contract wallets which implement ERC1271 https://eips.ethereum.org/EIPS/eip-1271 @param _owner The address which is a source of funds and has signed the Permit. @param _spender The address which is allowed to spend the funds. @param _value The amount of tokens to be spent. @param _deadline The timestamp after which the Permit is no longer valid. @param _v The bytes[64] of the valid secp256k1 signature of permit by owner @param _r The bytes[0:32] of the valid secp256k1 signature of permit by owner @param _s The bytes[32:64] of the valid secp256k1 signature of permit by owner @return True, if transaction completes successfully """ assert _owner != empty(address) assert block.timestamp <= _deadline nonce: uint256 = self.nonces[_owner] digest: bytes32 = keccak256( concat( b"\x19\x01", self._domain_separator(), keccak256(_abi_encode(EIP2612_TYPEHASH, _owner, _spender, _value, nonce, _deadline)) ) ) if _owner.is_contract: sig: Bytes[65] = concat(_abi_encode(_r, _s), slice(convert(_v, bytes32), 31, 1)) # reentrancy not a concern since this is a staticcall assert ERC1271(_owner).isValidSignature(digest, sig) == ERC1271_MAGIC_VAL else: assert ecrecover(digest, convert(_v, uint256), convert(_r, uint256), convert(_s, uint256)) == _owner self.allowance[_owner][_spender] = _value self.nonces[_owner] = unsafe_add(nonce, 1) log Approval(_owner, _spender, _value) return True @view @external def DOMAIN_SEPARATOR() -> bytes32: """ @notice EIP712 domain separator. @return bytes32 Domain Separator set for the current chain. """ return self._domain_separator() # ------------------------- AMM View Functions ------------------------------- @view @external def get_dx(i: int128, j: int128, dy: uint256) -> uint256: """ @notice Calculate the current input dx given output dy @dev Index values can be found via the `coins` public getter method @param i Index value for the coin to send @param j Index value of the coin to receive @param dy Amount of `j` being received after exchange @return Amount of `i` predicted """ return StableSwapViews(factory.views_implementation()).get_dx(i, j, dy, self) @view @external def get_dx_underlying(i: int128, j: int128, dy: uint256) -> uint256: """ @notice Calculate the current input dx given output dy @dev Swap involves base pool tokens (either i or j should be 0); If not, this method reverts. @param i Index value for the coin to send @param j Index value of the coin to receive @param dy Amount of `j` being received after exchange @return Amount of `i` predicted """ return StableSwapViews(factory.views_implementation()).get_dx_underlying(i, j, dy, self) @view @external def get_dy(i: int128, j: int128, dx: uint256) -> uint256: """ @notice Calculate the current output dy given input dx @dev Index values can be found via the `coins` public getter method @param i Index value for the coin to send @param j Index value of the coin to receive @param dx Amount of `i` being exchanged @return Amount of `j` predicted """ return StableSwapViews(factory.views_implementation()).get_dy(i, j, dx, self) @view @external def get_dy_underlying(i: int128, j: int128, dx: uint256) -> uint256: """ @notice Calculate the current output dy given input dx @dev Swap involves base pool tokens (either i or j should be 0); If not, this method reverts. @param i Index value for the coin to send @param j Index value of the coin to receive @param dx Amount of `i` being exchanged @return Amount of `j` predicted """ return StableSwapViews(factory.views_implementation()).get_dy_underlying(i, j, dx, self) @view @external def calc_withdraw_one_coin(_burn_amount: uint256, i: int128) -> uint256: """ @notice Calculate the amount received when withdrawing a single coin @param _burn_amount Amount of LP tokens to burn in the withdrawal @param i Index value of the coin to withdraw @return Amount of coin received """ return self._calc_withdraw_one_coin(_burn_amount, i)[0] @view @external @nonreentrant('lock') def totalSupply() -> uint256: """ @notice The total supply of pool LP tokens @return self.total_supply, 18 decimals. """ return self.total_supply @view @external @nonreentrant('lock') def get_virtual_price() -> uint256: """ @notice The current virtual price of the pool LP token @dev Useful for calculating profits. The method may be vulnerable to donation-style attacks if implementation contains rebasing tokens. For integrators, caution is advised. @return LP token virtual price normalized to 1e18 """ xp: uint256[N_COINS] = self._xp_mem(self._stored_rates(), self._balances()) D: uint256 = math.get_D([xp[0], xp[1]], self._A(), N_COINS) # D is in the units similar to DAI (e.g. converted to precision 1e18) # When balanced, D = n * x_u - total virtual value of the portfolio return D * PRECISION / self.total_supply @view @external def calc_token_amount( _amounts: uint256[N_COINS], _is_deposit: bool ) -> uint256: """ @notice Calculate addition or reduction in token supply from a deposit or withdrawal @param _amounts Amount of each coin being deposited @param _is_deposit set True for deposits, False for withdrawals @return Expected amount of LP tokens received """ return StableSwapViews(factory.views_implementation()).calc_token_amount( [_amounts[0], _amounts[1]], _is_deposit, self ) @view @external def A() -> uint256: return unsafe_div(self._A(), A_PRECISION) @view @external def A_precise() -> uint256: return self._A() @view @external def balances(i: uint256) -> uint256: """ @notice Get the current balance of a coin within the pool, less the accrued admin fees @param i Index value for the coin to query balance of @return Token balance """ return self._balances()[i] @view @external def get_balances() -> DynArray[uint256, MAX_COINS]: balances: uint256[N_COINS] = self._balances() return [balances[0], balances[1]] @view @external def stored_rates() -> DynArray[uint256, MAX_COINS]: rates: uint256[N_COINS] = self._stored_rates() return [rates[0], rates[1]] @view @external def dynamic_fee(i: int128, j: int128) -> uint256: """ @notice Return the fee for swapping between `i` and `j` @param i Index value for the coin to send @param j Index value of the coin to receive @return Swap fee expressed as an integer with 1e10 precision """ return StableSwapViews(factory.views_implementation()).dynamic_fee(i, j, self) # --------------------------- AMM Admin Functions ---------------------------- @external def ramp_A(_future_A: uint256, _future_time: uint256): assert msg.sender == factory.admin() # dev: only owner assert block.timestamp >= self.initial_A_time + MIN_RAMP_TIME assert _future_time >= block.timestamp + MIN_RAMP_TIME # dev: insufficient time _initial_A: uint256 = self._A() _future_A_p: uint256 = _future_A * A_PRECISION assert _future_A > 0 and _future_A < MAX_A if _future_A_p < _initial_A: assert _future_A_p * MAX_A_CHANGE >= _initial_A else: assert _future_A_p <= _initial_A * MAX_A_CHANGE self.initial_A = _initial_A self.future_A = _future_A_p self.initial_A_time = block.timestamp self.future_A_time = _future_time log RampA(_initial_A, _future_A_p, block.timestamp, _future_time) @external def stop_ramp_A(): assert msg.sender == factory.admin() # dev: only owner current_A: uint256 = self._A() self.initial_A = current_A self.future_A = current_A self.initial_A_time = block.timestamp self.future_A_time = block.timestamp # now (block.timestamp < t1) is always False, so we return saved A log StopRampA(current_A, block.timestamp) @external def set_new_fee(_new_fee: uint256, _new_offpeg_fee_multiplier: uint256): assert msg.sender == factory.admin() # set new fee: assert _new_fee <= MAX_FEE self.fee = _new_fee # set new offpeg_fee_multiplier: assert _new_offpeg_fee_multiplier * _new_fee <= MAX_FEE * FEE_DENOMINATOR # dev: offpeg multiplier exceeds maximum self.offpeg_fee_multiplier = _new_offpeg_fee_multiplier log ApplyNewFee(_new_fee, _new_offpeg_fee_multiplier) @external def set_ma_exp_time(_ma_exp_time: uint256, _D_ma_time: uint256): """ @notice Set the moving average window of the price oracles. @param _ma_exp_time Moving average window for the price oracle. It is time_in_seconds / ln(2). @param _D_ma_time Moving average window for the D oracle. It is time_in_seconds / ln(2). """ assert msg.sender == factory.admin() # dev: only owner assert unsafe_mul(_ma_exp_time, _D_ma_time) > 0 # dev: 0 in input values self.ma_exp_time = _ma_exp_time self.D_ma_time = _D_ma_time log SetNewMATime(_ma_exp_time, _D_ma_time)
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"name":"Transfer","inputs":[{"name":"sender","type":"address","indexed":true},{"name":"receiver","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true},{"name":"spender","type":"address","indexed":true},{"name":"value","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"TokenExchange","inputs":[{"name":"buyer","type":"address","indexed":true},{"name":"sold_id","type":"int128","indexed":false},{"name":"tokens_sold","type":"uint256","indexed":false},{"name":"bought_id","type":"int128","indexed":false},{"name":"tokens_bought","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"TokenExchangeUnderlying","inputs":[{"name":"buyer","type":"address","indexed":true},{"name":"sold_id","type":"int128","indexed":false},{"name":"tokens_sold","type":"uint256","indexed":false},{"name":"bought_id","type":"int128","indexed":false},{"name":"tokens_bought","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"AddLiquidity","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[]","indexed":false},{"name":"fees","type":"uint256[]","indexed":false},{"name":"invariant","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidity","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[]","indexed":false},{"name":"fees","type":"uint256[]","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityOne","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_id","type":"int128","indexed":false},{"name":"token_amount","type":"uint256","indexed":false},{"name":"coin_amount","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RemoveLiquidityImbalance","inputs":[{"name":"provider","type":"address","indexed":true},{"name":"token_amounts","type":"uint256[]","indexed":false},{"name":"fees","type":"uint256[]","indexed":false},{"name":"invariant","type":"uint256","indexed":false},{"name":"token_supply","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RampA","inputs":[{"name":"old_A","type":"uint256","indexed":false},{"name":"new_A","type":"uint256","indexed":false},{"name":"initial_time","type":"uint256","indexed":false},{"name":"future_time","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"StopRampA","inputs":[{"name":"A","type":"uint256","indexed":false},{"name":"t","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"ApplyNewFee","inputs":[{"name":"fee","type":"uint256","indexed":false},{"name":"offpeg_fee_multiplier","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetNewMATime","inputs":[{"name":"ma_exp_time","type":"uint256","indexed":false},{"name":"D_ma_time","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_A","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_offpeg_fee_multiplier","type":"uint256"},{"name":"_ma_exp_time","type":"uint256"},{"name":"_math_implementation","type":"address"},{"name":"_base_pool","type":"address"},{"name":"_coins","type":"address[]"},{"name":"_base_coins","type":"address[]"},{"name":"_rate_multipliers","type":"uint256[]"},{"name":"_asset_types","type":"uint8[]"},{"name":"_method_ids","type":"bytes4[]"},{"name":"_oracles","type":"address[]"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"exchange","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"exchange","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"exchange_received","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"exchange_received","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"exchange_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"exchange_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"_dx","type":"uint256"},{"name":"_min_dy","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"add_liquidity","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_min_mint_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"add_liquidity","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_min_mint_amount","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_one_coin","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"i","type":"int128"},{"name":"_min_received","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_one_coin","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"i","type":"int128"},{"name":"_min_received","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_imbalance","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_max_burn_amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity_imbalance","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_max_burn_amount","type":"uint256"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"_min_amounts","type":"uint256[2]"}],"outputs":[{"name":"","type":"uint256[2]"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"_min_amounts","type":"uint256[2]"},{"name":"_receiver","type":"address"}],"outputs":[{"name":"","type":"uint256[2]"}]},{"stateMutability":"nonpayable","type":"function","name":"remove_liquidity","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"_min_amounts","type":"uint256[2]"},{"name":"_receiver","type":"address"},{"name":"_claim_admin_fees","type":"bool"}],"outputs":[{"name":"","type":"uint256[2]"}]},{"stateMutability":"nonpayable","type":"function","name":"withdraw_admin_fees","inputs":[],"outputs":[]},{"stateMutability":"view","type":"function","name":"last_price","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"ema_price","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_p","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"price_oracle","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"D_oracle","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"transfer","inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"transferFrom","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"approve","inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"nonpayable","type":"function","name":"permit","inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"DOMAIN_SEPARATOR","inputs":[],"outputs":[{"name":"","type":"bytes32"}]},{"stateMutability":"view","type":"function","name":"get_dx","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_dx_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"dy","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_dy","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"dx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_dy_underlying","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"},{"name":"dx","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"calc_withdraw_one_coin","inputs":[{"name":"_burn_amount","type":"uint256"},{"name":"i","type":"int128"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_virtual_price","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"calc_token_amount","inputs":[{"name":"_amounts","type":"uint256[2]"},{"name":"_is_deposit","type":"bool"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"A","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"A_precise","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"balances","inputs":[{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_balances","inputs":[],"outputs":[{"name":"","type":"uint256[]"}]},{"stateMutability":"view","type":"function","name":"stored_rates","inputs":[],"outputs":[{"name":"","type":"uint256[]"}]},{"stateMutability":"view","type":"function","name":"dynamic_fee","inputs":[{"name":"i","type":"int128"},{"name":"j","type":"int128"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"ramp_A","inputs":[{"name":"_future_A","type":"uint256"},{"name":"_future_time","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"stop_ramp_A","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_new_fee","inputs":[{"name":"_new_fee","type":"uint256"},{"name":"_new_offpeg_fee_multiplier","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_ma_exp_time","inputs":[{"name":"_ma_exp_time","type":"uint256"},{"name":"_D_ma_time","type":"uint256"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"N_COINS","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"BASE_POOL","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"BASE_N_COINS","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"BASE_COINS","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"coins","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"fee","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"offpeg_fee_multiplier","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"admin_fee","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"initial_A","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"future_A","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"initial_A_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"future_A_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"admin_balances","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"ma_exp_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"D_ma_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"ma_last_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8"}]},{"stateMutability":"view","type":"function","name":"version","inputs":[],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"balanceOf","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"allowance","inputs":[{"name":"arg0","type":"address"},{"name":"arg1","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"nonces","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"salt","inputs":[],"outputs":[{"name":"","type":"bytes32"}]}]
Contract Creation Code
615ca43d81600a3d39f3fe71006157ac515034610969576020615ca16000396000516020602082615ca10160003960005111610969576020602082615ca101600039600051018082615ca10160803950506020615cc1600039600051600a602082615ca10160003960005111610969576020602082615ca101600039600051018082615ca10160c03950506020615d616000396000518060a01c61096957610100526020615d816000396000518060a01c61096957610120526020615da16000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561011b57905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b61016001526001018181186100ea575b5050806101405250506020615dc16000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561019457905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b6102800152600101818118610163575b5050806102605250506020615de16000396000516008602082615ca1016000396000511161096957602081615ca10160003960005160208160051b018083615ca101610380395050506020615e016000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561024d57905b60208160051b6020860101615ca1016000396000518060081c610969578160051b6104c0015260010181811861021c575b5050806104a05250506020615e216000396000516008602082615ca1016000396000511161096957602081615ca101600039600051600081600881116109695780156102c657905b60208160051b6020860101615ca1016000396000518060201b610969578160051b6105e00152600101818118610295575b5050806105c05250506020615e416000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561033f57905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b610700015260010181811861030e575b5050806106e0525050610120515a6004610800527f9c4258c4000000000000000000000000000000000000000000000000000000006108205261080050600060006108005161082060008686f19050905061532c5261532c516103a85760036102605111610969575b6101005161548c526101205161530c526102605160208160051b01600081601f0160051c600981116109695780156103fc57905b8060051b61026001518160051b60600161530c01526001018181186103dc575b505050506102605161534c526101405160208160051b01600081601f0160051c6009811161096957801561044d57905b8060051b61014001518160051b6101c00161530c015260010181811861042c575b505050506104a0511561096957600060051b6104c001516155ec5260026155ec511461560c52610380511561096957600060051b6103a0015161562c5260006008905b806108005261534c5161080051101561054a5761080051610260518110156109695760051b610280015163095ea7b36108205261530c51610840527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610860526020610820604461083c6000855af161050e573d600060003e3d6000fd5b3d61052557803b156109695760016108805261053e565b60203d1061096957610820518060011c61096957610880525b61088090505115610969575b60010181811861049057505060036155ec511861068357610140511561096957600060051b610160015163313ce567610800526020610800600461081c845afa610599573d600060003e3d6000fd5b60203d1061096957610800518060081c6109695761084052610840905051604d81116109695780600a0a905061566c52610140511561096957600060051b61016001516338d52e0f610800526020610800600461081c845afa610601573d600060003e3d6000fd5b60203d1061096957610800518060a01c610969576108405261084090505163313ce567610860526020610860600461087c845afa610644573d600060003e3d6000fd5b60203d1061096957610860518060081c610969576108a0526108a09050518060120360128111610969579050604d81116109695780600a0a905061568c525b336154ac5260646020615ce1600039600051026108005261080051600555610800516006556020615d016000396000516003556020615d216000396000516004556020615d4160003960005115610969576020615d4160003960005160145561f37460155542604052426060526106fb610820610928565b61082051601655670de0b6b3a7640000604052670de0b6b3a7640000606052610725610820610928565b610820516012556000600a556000600b556002600955600060015560006002556106e0511561096957600060051b61070001516105c0511561096957600060051b6105e001518060e01c90508060e01b818160e01c186109695790501761564c52602060805101600081601f0160051c600281116109695780156107c557905b8060051b608001518160051b6103a00161530c01526001018181186107a5575b505050602060c05101600081601f0160051c6002811161096957801561080757905b8060051b60c001518160051b6104000161530c01526001018181186107e7575b50505060206156ac5101600081601f0160051c6003811161096957801561084b57905b8060051b6103a00161530c01518160051b610820015260010181811861082a575b50505061082080516020820120905061574c52600143034061578c524661576c527fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564726108405261574c51610860527f1c54f243822e0e9a0a377610b81577e771b3efe79964e76636b0d5d10247950d61088052466108a052306108c05261578c516108e05260c0610820526108208051602082012090506157ac523360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6000610820526020610820a361530c61096e610000396157cc610000f35b6fffffffffffffffffffffffffffffffff60405111610969576fffffffffffffffffffffffffffffffff606051116109695760605160801b60405117815250565b600080fd60003560e01c60056005600783160261510801601b39600051600760078260ff16848460181c0260181c06028260081c61ffff160160193950600051818160181c14600336111661004f57612ff5565b8060fe16361034826001160217615103578060081c61ffff16565b600260405260206040f35b602061530c60403960206040f35b602061534c60403960206040f35b6020600435602061536c6000396000518110156151035760051b60800161530c0160403960206040f35b602060043560206154cc6000396000518110156151035760051b6101e00161530c0160403960206040f35b60035460405260206040f35b60045460405260206040f35b64012a05f20060405260206040f35b60055460405260206040f35b60065460405260206040f35b60075460405260206040f35b60085460405260206040f35b60043560095481101561510357600a015460405260206040f35b60145460405260206040f35b60155460405260206040f35b60165460405260206040f35b60208060405280604001602060206156ac60003960005101806156ac8339508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b602080604052806040016020602061570c600039600051018061570c8339508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b601260405260206040f35b60208060805260066040527f76372e302e30000000000000000000000000000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b6004358060a01c61510357604052601760405160205260005260406000205460605260206060f35b6004358060a01c615103576040526024358060a01c615103576060526018604051602052600052604060002080606051602052600052604060002090505460805260206080f35b6004358060a01c61510357604052601a60405160205260005260406000205460605260206060f35b602061578c60403960206040f35b33610a2052610346565b6084358060a01c61510357610a20525b60043580600f0b8118615103576109e05260243580600f0b811861510357610a0052600054600214615103576002600055602033610760526109e05161078052610a00516107a052604060446107c037610a2051610800526000610820526103af610a406144c4565b610a406003600055f35b33610a20526103d3565b6084358060a01c61510357610a20525b60043580600f0b8118615103576109e05260243580600f0b811861510357610a0052600054600214615103576002600055602061560c60003960005161510357602033610760526109e05161078052610a00516107a052604060446107c037610a20516108005260016108205261044b610a406144c4565b610a406003600055f35b336107a05261046f565b6084358060a01c615103576107a0525b60043580600f0b8118615103576107605260243580600f0b811861510357610780526000546002146151035760026000556107a05115615103576104b4610800613752565b61080060406107c060408360045afa50506104d061084061396e565b610840604061080060408360045afa50506040604060406107c060045afa5060406080604061080060045afa50610508610880613acb565b610880604061084060408360045afa505060e036610880376001610760511261054a57610760516001810380600f0b81186151035790506108a05260016108e0525b6107805161057a57602060206154cc6000396000511561510357600060051b6101e00161530c01610940396105bf565b610780516001810380600f0b81186151035790506108c05260016109005260206108c051602061536c6000396000518110156151035760051b60800161530c01610940395b6108e051610320526108a0516103405260443561036052336103805260006103a05260016107605112156105f45760006105fd565b60016107805112155b6103c05261060c61098061331f565b610980516109605261076051610623576001610629565b61078051155b61071d57610940516370a0823161098052306109a0526020610980602461099c845afa61065b573d600060003e3d6000fd5b60203d106151035761098090505161088052602061530c600039600051633df02124610980526108a0516109a0526108c0516109c052610960516109e052606435610a0052803b15615103576000610980608461099c6000855af16106c5573d600060003e3d6000fd5b50610940516370a0823161098052306109a0526020610980602461099c845afa6106f4573d600060003e3d6000fd5b60203d1061510357610980905051610880518082038281116151035790509050610880526108e3565b6108e051600181116151035760051b6108400151670de0b6b3a7640000610960516108e051600181116151035760051b6107c00151808202811583838304141715615103579050905004808201828110615103579050905061092052610920516102e0526040610300604061084060045afa50604061034060406107c060045afa506108e05161038052610900516103a0526107ba6109806140fc565b61098051610880526109005160018111615103576001018054610880518082038281116151035790509050815550600161078051126108d657610940516370a082316109a052306109c05260206109a060246109bc845afa610821573d600060003e3d6000fd5b60203d10615103576109a090505161098052602061530c600039600051631a4d01d26109a052610880516109c0526108c0516109e0526000610a0052803b156151035760006109a060646109bc6000855af1610882573d600060003e3d6000fd5b50610940516370a082316109a052306109c05260206109a060246109bc845afa6108b1573d600060003e3d6000fd5b60203d10615103576109a0905051610980518082038281116151035790509050610880525b6064356108805110615103575b6109405163a9059cbb610980526107a0516109a052610880516109c0526020610980604461099c6000855af161091e573d600060003e3d6000fd5b3d61093557803b156151035760016109e05261094e565b60203d1061510357610980518060011c615103576109e0525b6109e09050511561510357337fd013ca23e77a65003c2c659c5442c00c805371b7fc1ebd4c206c41d1536bd90b61076051610980526044356109a052610780516109c052610880516109e0526080610980a260206108806003600055f35b336104e0526109c6565b6064358060a01c615103576104e0525b6000546002146151035760026000556104e05115615103576109e9610520613b4e565b61052051610500526109fc61056061396e565b610560604061052060408360045afa5050610a186105a0613752565b6105a0604061056060408360045afa50506040610120604061056060045afa506040610160604061052060045afa50610500516101a052610a5a6105c0614754565b6105c0516105a0526019546105c05260406105e0604061052060045afa5060006002905b806106205261062051600181116151035760051b6004013515610b255761062051600181116151035760051b6105e001805161062051610320527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6103405261062051600181116151035760051b600401356103605233610380526040366103a037610b0b61064061331f565b610640518082018281106151035790509050815250610b2f565b6105c05115615103575b600101818118610a7e5750506040610120604061056060045afa50604061016060406105e060045afa50610500516101a052610b6c610640614754565b61064051610620526105a05161062051111561510357606036610640376105c05115610f13576060366106a0376105a05161062051808201828110615103579050905060011c610700526040366107203760035460011b60021c6107605260006002905b80610780526106205161078051600181116151035760051b610520015180820281158383830414171561510357905090506105a051801561510357808204905090506106a05261078051600181116151035760051b6105e001516106e0526106e0516106a05111610c4d576106a0516106e051036106c052610c5b565b6106e0516106a051036106c0525b670de0b6b3a764000061078051600181116151035760051b610560015161078051600181116151035760051b61052001516106e051808201828110615103579050905080820281158383830414171561510357905090500461072052610720516040526107005160605261076051608052610cd76107a0613c59565b6107a051610740526402540be400610740516106c05180820281158383830414171561510357905090500461078051600181116151035760051b61064001526107805160095481101561510357600a0180546402540be40061078051600181116151035760051b610640015164012a05f20081028164012a05f20082041861510357905004808201828110615103579050905081555061078051600181116151035760051b6105e001805161078051600181116151035760051b61064001518082038281116151035790509050815250600101818118610bd057505060406040604061056060045afa506040608060406105e060045afa50610dda6107c0613acb565b6107c0604061078060408360045afa5050602061548c6000396000516350e7277d6107c0526060806107e052806107e001600061078051610980526107a0516109a0526002610960526000610960518084528060051b60008260088111615103578015610e6157905b8060051b61098001518160051b602089010152600101818118610e43575b50508201602001915050905090508101905061050051610800526002610820525060206107c06101846107dc845afa610e9f573d600060003e3d6000fd5b60203d10615103576107c0905051610620526105a0516105c051610620516105a0518082038281116151035790509050808202811583838304141715615103579050905004610680526040610140604061078060045afa506105005161018052610620516101a052610f8e613f6856610f8e565b61062051610680526106205160405261062051606052610f346106a0612ffb565b6106a051601355601654604052610f4c6106e0613d19565b6106e060406106a060408360045afa5050426106c0511015610f8e57426106c0526106a0516040526106c051606052610f866106e0612ffb565b6106e0516016555b6044356106805110156110015760146106a0527f536c697070616765207363726577656420796f750000000000000000000000006106c0526106a0506106a051806106c001601f826000031636823750506308c379a061066052602061068052601f19601f6106a051011660440161067cfd5b6105c0516106805180820182811061510357905090506105c05260176104e0516020526000526040600020546106a052610680516106a0510160176104e0516020526000526040600020556105c0516019556104e05160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef610680516106c05260206106c0a3337f189c623b666b1b45b83d7178f39b8c087cb09774317ca2f53c2d3c3726f222a26080806106c052806106c0016000604060046109a0376002610980526000610980518084528060051b6000826008811161510357801561110457905b8060051b6109a001518160051b6020890101526001018181186110e6575b505082016020019150509050905081019050806106e052806106c001600061064051610ac05261066051610ae0526002610aa0526000610aa0518084528060051b6000826008811161510357801561117657905b8060051b610ac001518160051b602089010152600101818118611158575b50508201602001915050905090508101905061062051610700526105c051610720526106c0a260206106806003600055f35b336107a0526111c2565b6064358060a01c615103576107a0525b60243580600f0b81186151035761078052600054600214615103576002600055600435156151035760c0366107c03760043561020052610780516102205261120b610880614853565b61088080516107c05260208101516107e05260408101604061080060408360045afa505060808101516108405260a081015161086052506044356107c05110156112b5576018610880527f4e6f7420656e6f75676820636f696e732072656d6f76656400000000000000006108a0526108805061088051806108a001601f826000031636823750506308c379a061084052602061086052601f19601f61088051011660440161085cfd5b6107805160095481101561510357600a0180546402540be4006107e05164012a05f20081028164012a05f2008204186151035790500480820182811061510357905090508155503360405260043560605261130e614e6a565b610780516040526107c0516060526107a05160805261132b613569565b337f6f48129db1f37ccb9cc5dd7e119cb32750cabdf75b48375d730d26ce3659bbe161078051610880526004356108a0526107c0516108c0526019546108e0526080610880a26040610140604061080060045afa506108405161018052610860516101a052611398613f68565b60206107c06003600055f35b336104c0526113be565b6064358060a01c615103576104c0525b6000546002146151035760026000556113d8610500613b4e565b610500516104e0526113eb610540613752565b610540604061050060408360045afa505061140761058061396e565b610580604061054060408360045afa50506040610120604061050060045afa506040610160604061054060045afa506104e0516101a0526114496105a0614754565b6105a0516105805260406105a0604061054060045afa5060006002905b806105e0526105e051600181116151035760051b60040135156114e8576105e051600181116151035760051b6105a00180516105e051600181116151035760051b6004013580820382811161510357905090508152506105e0516040526105e051600181116151035760051b600401356060526104c0516080526114e8613569565b6001018181186114665750506040610120604061050060045afa50604061016060406105a060045afa506104e0516101a052611525610600614754565b610600516105e05260035460011b60021c61060052610580516105e051808201828110615103579050905060011c6106205260e0366106403760006002905b80610720526105e05161072051600181116151035760051b6105400151808202811583838304141715615103579050905061058051801561510357808204905090506106c05261072051600181116151035760051b6105a0015161070052610700516106c051116115e1576106c05161070051036106e0526115ef565b610700516106c051036106e0525b670de0b6b3a764000061072051600181116151035760051b610500015161072051600181116151035760051b61054001516107005180820182811061510357905090508082028115838383041417156151035790509050046106a0526106a051604052610620516060526106005160805261166b610740613c59565b61074051610680526402540be400610680516106e05180820281158383830414171561510357905090500461072051600181116151035760051b61064001526107205160095481101561510357600a0180546402540be40061072051600181116151035760051b610640015164012a05f20081028164012a05f20082041861510357905004808201828110615103579050905081555061072051600181116151035760051b6105a001805161072051600181116151035760051b610640015180820382811161510357905090508152506001018181186115645750506040610120604061050060045afa50604061016060406105a060045afa506104e0516101a052611778610720614754565b610720516105e05260406040604061050060045afa506040608060406105a060045afa506117a7610720613acb565b610720604061076060408360045afa50506104e0516107a0526105e0516107c0526080610140608061076060045afa506117df613f68565b6019546107205261058051610580516105e051808203828111615103579050905061072051808202811583838304141715615103579050905004600181018181106151035790506107405260026107405110615103576044356107405111156118a8576014610760527f536c697070616765207363726577656420796f750000000000000000000000006107805261076050610760518061078001601f826000031636823750506308c379a061072052602061074052601f19601f61076051011660440161073cfd5b33604052610740516060526118bb614e6a565b337f3631c28b1f9dd213e0319fb167b554d76b6c283a41143eb400a0d1adb1af1755608080610760528061076001600060406004610a40376002610a20526000610a20518084528060051b6000826008811161510357801561193757905b8060051b610a4001518160051b602089010152600101818118611919575b50508201602001915050905090508101905080610780528061076001600061064051610b605261066051610b80526002610b40526000610b40518084528060051b600082600881116151035780156119a957905b8060051b610b6001518160051b60208901015260010181811861198b575b5050820160200191505090509050810190506105e0516107a052610720516107405180820382811161510357905090506107c052610760a260206107406003600055f35b336102a05260016102c052611a36565b6064358060a01c615103576102a05260016102c052611a36565b6064358060a01c615103576102a0526084358060011c615103576102c0525b6000546002146151035760026000556019546102e052600435156151035760403661030037611a6661038061396e565b610380604061034060408360045afa505060006103805260006002905b806103a0526102e0516103a051600181116151035760051b6103400151600435808202811583838304141715615103579050905004610380526103a051600181116151035760051b60240135610380511015611b645760306103c0527f5769746864726177616c20726573756c74656420696e20666577657220636f696103e0527f6e73207468616e20657870656374656400000000000000000000000000000000610400526103c0506103c051806103e001601f826000031636823750506308c379a06103805260206103a052601f19601f6103c051011660440161039cfd5b610380516103a051600181116151035760051b61030001526103a051604052610380516060526102a051608052611b99613569565b600101818118611a8357505033604052600435606052611bb7614e6a565b601654604052611bc86103e0613d19565b6103e060406103a060408360045afa50506013546103e0526fffffffffffffffffffffffffffffffff6103e0511661040052610400516102e051610400516004358082028115838383041417156151035790509050048082038281116151035790509050610460526103e0516040526015546060526103c051608052611c4f610420613e3a565b610420516104805260406040604061046060045afa50611c70610440612ffb565b61044051601355426103c0511015611ca857426103c0526103a0516040526103c051606052611ca0610420612ffb565b610420516016555b337f347ad828e58cbe534d8f6b67985d791360756b18f0d95fd9f197a66cc46480ea6060806104205280610420016000610300516106e052610320516107005260026106c05260006106c0518084528060051b60008260088111615103578015611d2c57905b8060051b6106e001518160051b602089010152600101818118611d0e575b5050820160200191505090509050810190508061044052806104200160006000825260006000600060088111615103578015611d7b57905b60008160051b602087010152600101818118611d64575b5050810160200190509050810190506004356102e0510361046052610420a26102c05115611dab57611dab614eda565b6103005161042052610320516104405260406104206003600055f35b611dcf614eda565b005b600435615103576fffffffffffffffffffffffffffffffff6012541660405260206040f35b6004356151035760125460801c60405260206040f35b60043561510357611e1e610220613b4e565b6102205161020052611e31610260613752565b610260604061032060408360045afa5050611e4d6102a061396e565b6102a0604061036060408360045afa505060806040608061032060045afa50611e776102e0613acb565b6102e0604061022060408360045afa5050602061548c6000396000516350e7277d610280526060806102a052806102a0016000610220516104405261024051610460526002610420526000610420518084528060051b60008260088111615103578015611efe57905b8060051b61044001518160051b602089010152600101818118611ee0575b505082016020019150509050905081019050610200516102c05260026102e05250602061028061018461029c845afa611f3c573d600060003e3d6000fd5b60203d106151035761028090505161026052602060406040604061022060045afa50610200516080526102605160a052611f77610280613d3e565b610280f35b600054600214615103576004356151035760206012546040526014546060526fffffffffffffffffffffffffffffffff60165416608052611fbe610140613e3a565b610140f35b60005460021461510357602060135460405260155460605260165460801c608052611fef610140613e3a565b610140f35b6004358060a01c6151035760c0523360405260c05160605260243560805261201a615083565b600160e052602060e0f35b6004358060a01c6151035760c0526024358060a01c6151035760e05260c05160405260e05160605260443560805261205b615083565b601860c051602052600052604060002080336020526000526040600020905054610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100511461211a576101005160443580820382811161510357905090506101205261012051601860c0516020526000526040600020803360205260005260406000209050553360c0517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92561012051610140526020610140a35b6001610120526020610120f35b6004358060a01c615103576040526024356018336020526000526040600020806040516020526000526040600020905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f35b6004358060a01c61510357610120526024358060a01c61510357610140526084358060081c6151035761016052610120511561510357606435421161510357601a6101205160205260005260406000205461018052600060026101c0527f19010000000000000000000000000000000000000000000000000000000000006101e0526101c080516020820183610320018151815250508083019250505061223b610200614fee565b610200518161032001526020810190507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961024052610120516102605261014051610280526044356102a052610180516102c0526064356102e05260c061022052610220805160208201209050816103200152602081019050806103005261030090508051602082012090506101a052610120513b15612409576000604060a46102603760406102405261024080516020820183610320018281848460045afa50505080830192505050610160516102a0526102a0601f810180516102e0525060016102c0526102c09050805160208201836103200181518152505080830192505050806103005261030090506020815101806101c0828460045afa5050507f1626ba7e0000000000000000000000000000000000000000000000000000000061012051631626ba7e6102405260406101a051610260528061028052806102600160206101c051018082826101c060045afa50508051806020830101601f82600003163682375050601f19601f82516020010116905081015050602061024060c461025c845afa6123f1573d600060003e3d6000fd5b60203d1061510357610240905051186151035761244a565b610120516000610240526101a0516101c052610160516101e05260a4356102005260c43561022052602061024060806101c060015afa506102405118615103575b60443560186101205160205260005260406000208061014051602052600052604060002090505560016101805101601a6101205160205260005260406000205561014051610120517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256044356101c05260206101c0a360016101c05260206101c0f35b60206124da610120614fee565b610120f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa61252e573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c09050516383aa796a60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa612585573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa6125e2573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163d6fc10ab60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa612639573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa612696573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c0905051630c601c2c60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa6126ed573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa61274a573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163c02c60a660e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa6127a1573d600060003e3d6000fd5b60203d106151035760e09050f35b60243580600f0b8118615103576107805260206004356102005261078051610220526127dc6107a0614853565b6107a0f35b6000546002146151035760195460405260206040f35b6000546002146151035761280c610240613752565b610240604061030060408360045afa505061282861028061396e565b610280604061034060408360045afa505060806040608061030060045afa506128526102c0613acb565b6102c0604061020060408360045afa5050602061548c6000396000516350e7277d610280526060806102a052806102a0016000610200516104405261022051610460526002610420526000610420518084528060051b600082600881116151035780156128d957905b8060051b61044001518160051b6020890101526001018181186128bb575b5050820160200191505090509050810190506128f6610260613b4e565b610260516102c05260026102e05250602061028061018461029c845afa612922573d600060003e3d6000fd5b60203d10615103576102809050516102405261024051670de0b6b3a7640000810281670de0b6b3a764000082041861510357905060195480156151035780820490509050610260526020610260f35b6044358060011c61510357604052602060206154ac60003960005163e31593d8606052602060606004607c845afa6129ae573d600060003e3d6000fd5b60203d10615103576060518060a01c6151035760a05260a090505163fb79eb2760c05260608060e0528060e001600060406004610280376002610260526000610260518084528060051b60008260088111615103578015612a2957905b8060051b61028001518160051b602089010152600101818118612a0b575b50508201602001915050905090508101905060405161010052306101205250602060c061018460dc845afa612a63573d600060003e3d6000fd5b60203d106151035760c09050f35b6064612a7d60c0613b4e565b60c0510460e052602060e0f35b6020612a9660c0613b4e565b60c0f35b6020612aa761020061396e565b610200600435600181116151035760051b81019050f35b612ac961024061396e565b610240604061020060408360045afa50506020806102405280610240016000610200516103a052610220516103c0526002610380526000610380518084528060051b60008260088111615103578015612b3c57905b8060051b6103a001518160051b602089010152600101818118612b1e575b505082016020019150509050905081019050610240f35b612b5e610180613752565b610180604061014060408360045afa50506020806101805280610180016000610140516102e052610160516103005260026102c05260006102c0518084528060051b60008260088111615103578015612bd157905b8060051b6102e001518160051b602089010152600101818118612bb3575b505082016020019150509050905081019050610180f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa612c37573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163a63530bd60e05260405161010052606051610120523061014052602060e0606460fc845afa612c87573d600060003e3d6000fd5b60203d106151035760e09050f35b60206154ac60003960005163f851a44060c052602060c0600460dc845afa612cc2573d600060003e3d6000fd5b60203d106151035760c0518060a01c6151035761010052610100905051331861510357600754620151808101818110615103579050421061510357426201518081018181106151035790506024351061510357612d1f60e0613b4e565b60e05160c0526004356064810281606482041861510357905060e05260043515612d5157620f423f6004351115612d54565b60005b156151035760c05160e05110612d845760c051600a810281600a82041861510357905060e0511161510357612da0565b60c05160e051600a810281600a82041861510357905010615103575b60c05160055560e051600655426007556024356008557fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c25460c0516101005260e051610120524261014052602435610160526080610100a1005b60206154ac60003960005163f851a44060c052602060c0600460dc845afa612e26573d600060003e3d6000fd5b60203d106151035760c0518060a01c6151035761010052610100905051331861510357612e5360e0613b4e565b60e05160c05260c05160055560c05160065542600755426008557f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193860c05160e0524261010052604060e0a1005b60206154ac60003960005163f851a440604052602060406004605c845afa612ecd573d600060003e3d6000fd5b60203d10615103576040518060a01c61510357608052608090505133186151035764012a05f20060043511615103576004356003556802b5e3af16b1880000602435600435808202811583838304141715615103579050905011615103576024356004557f750d10a7f37466ce785ee6bcb604aac543358db42afbcc332a3c12a49c80bf6d6040600460403760406040a1005b60206154ac60003960005163f851a440604052602060406004605c845afa612f8d573d600060003e3d6000fd5b60203d10615103576040518060a01c6151035760805260809050513318615103576024356004350215615103576004356014556024356015557f68dc4e067dff1862b896b7a0faf55f97df1a60d0aaa79481b69d675f2026a28c6040600460403760406040a1005b60006000fd5b6fffffffffffffffffffffffffffffffff60405111615103576fffffffffffffffffffffffffffffffff606051116151035760605160801b60405117815250565b602061532c6000396000511561317d5760006080526000602061534c600039600051600881116151035780156130d357905b806101a05260605160008112615103576101a051186130aa5760805160078111615103576040518160051b60a0015260018101608052506130c8565b608051600781116151035760008160051b60a0015260018101608052505b60010181811861306e575b5050602061530c60003960005163b72df5de6101a0526040806101c052806101c00160006080518083528060051b6000826008811161510357801561313157905b8060051b60a001518160051b602088010152600101818118613114575b5050820160200191505090508101905060006101e0525060206101a06101646101bc6000855af1613167573d600060003e3d6000fd5b60203d10615103576101a090505181525061331d565b6020600260206154cc6000396000511061510357600160051b6101e00161530c016080396080516370a0823160c0523060e052602060c0602460dc845afa6131ca573d600060003e3d6000fd5b60203d106151035760c090505160a0526002602061534c600039600051186132565760403660c037604051606051600181116151035760051b60c00152602061530c600039600051630b4c7e4d610100526040610120604060c060045afa50600061016052803b15615103576000610100606461011c6000855af1613254573d600060003e3d6000fd5b505b6003602061534c600039600051186132d25760603660c037604051606051600281116151035760051b60c00152602061530c600039600051634515cef3610120526060610140606060c060045afa5060006101a052803b15615103576000610120608461013c6000855af16132d0573d600060003e3d6000fd5b505b6080516370a0823160c0523060e052602060c0602460dc845afa6132fb573d600060003e3d6000fd5b60203d106151035760c090505160a05180820382811161510357905090508152505b565b60206103205160206154cc6000396000518110156151035760051b6101e00161530c016103e039600061040052600061034051121561335f576000613368565b60016103205118155b1561339a57602061034051602061536c6000396000518110156151035760051b60800161530c016103e0396001610400525b6103e0516370a082316104405230610460526020610440602461045c845afa6133c8573d600060003e3d6000fd5b60203d1061510357610440905051610420526103a0516134bd576103605115615103576103e0516323b872dd6104405261038051610460523061048052610360516104a0526020610440606461045c6000855af161342b573d600060003e3d6000fd5b3d61344257803b156151035760016104c05261345b565b60203d1061510357610440518060011c615103576104c0525b6104c090505115615103576103e0516370a082316104405230610460526020610440602461045c845afa613494573d600060003e3d6000fd5b60203d1061510357610440905051610420518082038281116151035790509050610420526134f9565b610400516134f9576104205161032051600181116151035760010154808203828111615103579050905061042052610360516104205110615103575b6104005115613539576103c051156135175761042051815250613567565b610420516040526103405160605261353061044061303c565b61044051610420525b6103205160018111615103576001018054610420518082018281106151035790509050815550610420518152505b565b6080511561510357602061560c60003960005161363b57604051600181116151035760010180546060518082038281116151035790509050815550602060405160206154cc6000396000518110156151035760051b6101e00161530c0160003960005163a9059cbb60a05260805160c05260605160e052602060a0604460bc6000855af16135fc573d600060003e3d6000fd5b3d61361357803b156151035760016101005261362b565b60203d106151035760a0518060011c61510357610100525b6101009050511561510357613750565b602060405160206154cc6000396000518110156151035760051b6101e00161530c016000396000516370a0823160c0523060e052602060c0602460dc845afa613689573d600060003e3d6000fd5b60203d106151035760c090505160a052602060405160206154cc6000396000518110156151035760051b6101e00161530c0160003960005163a9059cbb60c05260805160e05260605161010052602060c0604460dc6000855af16136f2573d600060003e3d6000fd5b3d61370957803b1561510357600161012052613721565b60203d106151035760c0518060011c61510357610120525b610120905051156151035760a05160605180820382811161510357905090506040516001811161510357600101555b565b602061562c604039602061530c60003960005163bb7b8b80608052602060806004609c845afa613787573d600060003e3d6000fd5b60203d10615103576080905051606052600160206155ec600039600051186137bb57602061564c60003960005115156137be565b60005b61387857600360206155ec6000396000511861395f57670de0b6b3a7640000604051602060206154cc6000396000511561510357600060051b6101e00161530c016000396000516307a2d13a608052602061566c60a039602060806024609c845afa61382f573d600060003e3d6000fd5b60203d106151035760809050518082028115838383041417156151035790509050602061568c60003960005180820281158383830414171561510357905090500460405261395f565b602061564c60003960005173ffffffffffffffffffffffffffffffffffffffff811690508060a01c615103575a7fffffffff00000000000000000000000000000000000000000000000000000000602061564c6000396000511660e052602060c05260c050602061012060c05160e08585fa905090506138fd573d600060003e3d6000fd5b3d602081183d6020100218610100526101008051608052602081015160a052506020608051186151035760a05160805160200360031b1c60c052670de0b6b3a764000060405160c0518082028115838383041417156151035790509050046040525b6040816040604060045afa5050565b60403660403760095460208160051b01600081601f0160051c600981116151035780156139af57905b80600901548160051b60800152600101818118613997575b5050505060006002905b806101a052602061560c600039600051613a18576101a0516001811161510357600101546101a0516080518110156151035760051b60a0015180820382811161510357905090506101a051600181116151035760051b60400152613ab0565b60206101a05160206154cc6000396000518110156151035760051b6101e00161530c016000396000516370a082316101c052306101e05260206101c060246101dc845afa613a6b573d600060003e3d6000fd5b60203d10615103576101c09050516101a0516080518110156151035760051b60a0015180820382811161510357905090506101a051600181116151035760051b604001525b6001018181186139b95750506040816040604060045afa5050565b60403660c03760006002905b8061010052670de0b6b3a764000061010051600181116151035760051b6040015161010051600181116151035760051b6080015180820281158383830414171561510357905090500461010051600181116151035760051b60c00152600101818118613ad7575050604081604060c060045afa5050565b6008546040526006546060526040514210613b7257606051815250613c5756613c57565b60055460805260075460a05260805160605111613bf457608051606051608051034260a0518082038281116151035790509050808202811583838304141715615103579050905060405160a0518082038281116151035790509050801561510357808204905090508082038281116151035790509050815250613c5756613c57565b608051608051606051034260a0518082038281116151035790509050808202811583838304141715615103579050905060405160a05180820382811161510357905090508015615103578082049050905080820182811061510357905090508152505b565b60045460a0526402540be40060a05111613c7857608051815250613d17565b60405160605180820182811061510357905090506fffffffffffffffffffffffffffffffff8111615103576002810a905060c0526402540be4006402540be40060a051038060021b818160021c186151035790506040518082028115838383041417156151035790509050606051808202811583838304141715615103579050905060c051801561510357808204905090500160805160a05102048152505b565b6fffffffffffffffffffffffffffffffff60405116815260405160801c602082015250565b60805160011b60c05260a05160021c60e05260006002905b806101005260e05160a051808202811583838304141715615103579050905061010051600181116151035760051b604001518015615103578082049050905060e052600101818118613d56575050606460c051604051808202811583838304141715615103579050905004610100526101005160605160e0516040518082028115838383041417156151035790509050048082018281106151035790509050670de0b6b3a7640000810281670de0b6b3a76400008204186151035790506101005160e051808201828110615103579050905080156151035780820490509050815250565b6fffffffffffffffffffffffffffffffff6040511660a05260405160801c60c052426080511015613f5f57602061548c60003960005163e46751e361010052606051670de0b6b3a7640000608051420302048060ff1c615103577f8000000000000000000000000000000000000000000000000000000000000000811461510357600003610120526020610100602461011c845afa613ede573d600060003e3d6000fd5b60203d106151035761010090505160e052670de0b6b3a764000060a05160e05180670de0b6b3a764000003670de0b6b3a76400008111615103579050808202811583838304141715615103579050905060c05160e0518082028115838383041417156151035790509050808201828110615103579050905004815250613f66565b60c0518152505b565b601654604052613f79610200613d19565b61020060406101c060408360045afa505060125461020052610200516102205260406040604061014060045afa50610180516080526101a05160a052613fc0610260613d3e565b6102605161024052610240511561403d5761024051671bc16d674ec80000818118671bc16d674ec800008310021890506102a052610200516040526014546060526101c051608052614013610260613e3a565b610260516102c0526040604060406102a060045afa50614034610280612ffb565b61028051610220525b610220516012556101a0516102a0526013546040526015546060526101e05160805261406a610260613e3a565b610260516102c0526040604060406102a060045afa5061408b610280612ffb565b6102805160135560006002905b80610260524261026051600181116151035760051b6101c0015110156140ce574261026051600181116151035760051b6101c001525b6001018181186140985750506101c0516040526101e0516060526140f3610260612ffb565b61026051601655565b6141076103e0613b4e565b6103e0516103c052602061548c6000396000516350e7277d610400526060806104205280610420016000610300516105c052610320516105e05260026105a05260006105a0518084528060051b6000826008811161510357801561418557905b8060051b6105c001518160051b602089010152600101818118614167575b5050820160200191505090509050810190506103c0516104405260026104605250602061040061018461041c845afa6141c3573d600060003e3d6000fd5b60203d10615103576104009050516103e052602061548c60003960005163aa3ded9b6104205260e061038051610440526103a051610460526102e05161048052806104a05280610440016000610300516106605261032051610680526002610640526000610640518084528060051b6000826008811161510357801561426357905b8060051b61066001518160051b602089010152600101818118614245575b5050820160200191505090509050810190506103c0516104c0526103e0516104e05260026105005250602061042061020461043c845afa6142a9573d600060003e3d6000fd5b60203d1061510357610420905051610400526103a051600181116151035760051b610300015161040051808203828111615103579050905060018103818111615103579050610420526402540be4006104205161038051600181116151035760051b61030001516102e051808201828110615103579050905060011c6040526103a051600181116151035760051b610300015161040051808201828110615103579050905060011c606052600354608052614365610460613c59565b610460518082028115838383041417156151035790509050046104405261042051610440518082038281116151035790509050670de0b6b3a7640000810281670de0b6b3a76400008204186151035790506103a051600181116151035760051b610340015180156151035780820490509050610420526103a05160095481101561510357600a0180546103a051600181116151035760051b61034001516402540be4006104405164012a05f20081028164012a05f20082041861510357905004670de0b6b3a7640000810281670de0b6b3a76400008204186151035790500480820182811061510357905090508155506040610460604061030060045afa506102e05161038051600181116151035760051b6104600152610400516103a051600181116151035760051b61046001526040610140604061046060045afa506103c051610180526103e0516101a0526144bb613f68565b61042051815250565b6107a0516107805114615103576107c05115615103576144e5610880613752565b610880604061084060408360045afa50506145016108c061396e565b6108c0604061088060408360045afa505060406040604061084060045afa5060406080604061088060045afa50614539610900613acb565b61090060406108c060408360045afa505061078051610320527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610340526107c051610360526107605161038052610820516103a05260006103c0526145a061092061331f565b610920516109005261078051600181116151035760051b6108c00151670de0b6b3a76400006109005161078051600181116151035760051b6108400151808202811583838304141715615103579050905004808201828110615103579050905061092052610920516102e052604061030060406108c060045afa506040610340604061084060045afa5061078051610380526107a0516103a0526146456109606140fc565b61096051610940526107e0516109405110156146e657602e610960527f45786368616e676520726573756c74656420696e20666577657220636f696e73610980527f207468616e2065787065637465640000000000000000000000000000000000006109a05261096050610960518061098001601f826000031636823750506308c379a061092052602061094052601f19601f61096051011660440161093cfd5b6107a0516040526109405160605261080051608052614703613569565b337f8b3e96f2b889fa771c53c981b40daf005f63f637f1869f707052d15a3dd97140610780516109605261090051610980526107a0516109a052610940516109c0526080610960a261094051815250565b60406040604061012060045afa5060406080604061016060045afa5061477b610200613acb565b61020060406101c060408360045afa5050602061548c6000396000516350e7277d6102005260608061022052806102200160006101c0516103c0526101e0516103e05260026103a05260006103a0518084528060051b6000826008811161510357801561480257905b8060051b6103c001518160051b6020890101526001018181186147e4575b5050820160200191505090509050810190506101a0516102405260026102605250602061020061018461021c845afa614840573d600060003e3d6000fd5b60203d1061510357610200905051815250565b61485e610260613b4e565b61026051610240526148716102a0613752565b6102a0604061026060408360045afa50506040610360604061026060045afa5061489c6102e061396e565b6102e060406103a060408360045afa505060806040608061036060045afa506148c6610320613acb565b61032060406102a060408360045afa5050602061548c6000396000516350e7277d6103005260608061032052806103200160006102a0516104c0526102c0516104e05260026104a05260006104a0518084528060051b6000826008811161510357801561494d57905b8060051b6104c001518160051b60208901015260010181811861492f575b505082016020019150509050905081019050610240516103405260026103605250602061030061018461031c845afa61498b573d600060003e3d6000fd5b60203d10615103576103009050516102e052601954610300526102e051610200516102e05180820281158383830414171561510357905090506103005180156151035780820490509050808203828111615103579050905061032052602061548c600039600051637982c3406103605260a06102405161038052610220516103a052806103c052806103800160006102a051610560526102c051610580526002610540526000610540518084528060051b60008260088111615103578015614a6d57905b8060051b61056001518160051b602089010152600101818118614a4f575b505082016020019150509050905081019050610320516103e0526002610400525060206103606101c461037c845afa614aab573d600060003e3d6000fd5b60203d10615103576103609050516103405260035460011b60021c61036052604061038060406102a060045afa506102e05161032051808201828110615103579050905060021c6103c0526080366103e03760006002905b806104605260006103e05261046051600181116151035760051b6102a0015161040052610220516104605118614b9857610400516103205180820281158383830414171561510357905090506102e051801561510357808204905090506103405180820382811161510357905090506103e0526104005161034051808201828110615103579050905060011c61042052614be4565b61040051610400516103205180820281158383830414171561510357905090506102e0518015615103578082049050905080820382811161510357905090506103e05261040051610420525b610420516040526103c05160605261036051608052614c04610480613c59565b6104805161044052610400516402540be400610440516103e051808202811583838304141715615103579050905004808203828111615103579050905061046051600181116151035760051b6103800152600101818118614b0357505061022051600181116151035760051b6103800151602061548c600039600051637982c3406104805260a0610240516104a052610220516104c052806104e052806104a001600061038051610680526103a0516106a0526002610660526000610660518084528060051b60008260088111615103578015614cfb57905b8060051b61068001518160051b602089010152600101818118614cdd575b50508201602001915050905090508101905061032051610500526002610520525060206104806101c461049c845afa614d39573d600060003e3d6000fd5b60203d106151035761048090505180820382811161510357905090506104605261022051600181116151035760051b6102a00151610340518082038281116151035790509050670de0b6b3a7640000810281670de0b6b3a764000082041861510357905061022051600181116151035760051b6102600151801561510357808204905090506104805261022051600181116151035760051b61026001516104605160018103818111615103579050670de0b6b3a7640000810281670de0b6b3a764000082041861510357905004610460526103405161022051600181116151035760051b6102a001526104605181526104805161046051808203828111615103579050905060208201526040810160408160406102a060045afa50506102405160808201526103205160a082015250565b6019546060518082038281116151035790509050601955601760405160205260005260406000208054606051808203828111615103579050905081555060006040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a3565b60206154ac60003960005163cab4d3db610160526020610160600461017c845afa614f0a573d600060003e3d6000fd5b60203d1061510357610160518060a01c615103576101a0526101a09050516101405261014051614f3957614fec565b60095460208160051b01600081601f0160051c60098111615103578015614f7557905b80600901548160051b6101600152600101818118614f5c575b5050505060006002905b806102805261028051610160518110156151035760051b610180015115614fd0576102805160405261028051610160518110156151035760051b610180015160605261014051608052614fd0613569565b600101818118614f7f5750506000600a556000600b5560026009555b565b602061576c6000396000514614615078577fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472606052602061574c6080397f1c54f243822e0e9a0a377610b81577e771b3efe79964e76636b0d5d10247950d60a0524660c0523060e052602061578c6101003960c06040526040805160208201209050815250615081565b60206157ac8239505b565b601760405160205260005260406000208054608051808203828111615103579050905081555060176060516020526000526040600020805460805180820182811061510357905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160a052602060a0a3565b600080fd062951300a008151a0090073526b0604dc521e0b002b52db07054452950a000d517606020251df09bb7b8b8027f705140522880131057e3db03003b985f446c1d02a7105015c28382ea0457ecebe0002f62529357750006a05551a65882df90554fd4d5002180576a2f0f02a8a0576a9cd3e2be845a6417ed604558544ee1986045fa571511a5e007505dd62ed3e02af45d52d5b860091250e71d1b925936514f059792abe0570a08231028725fee3f7f900fe054903b0d12a9a253da575a1008305fd0684b12b530595d89b4101c4051ddc3b01016f05313ce567020d0507211ef726fb65cc2b27d727af455e0d443f2647653eb1719f19fd85c661065700bb258edfdd5f00f20590d208371df625d505accf2193e5687276531f7c25db1bb01b1a17a565bbea6b2f6045bfa0b133031e05ddca3f4300e605ed8e84f3297165095ea7b321274506fdde03017b05e310327313a465a9059cbb1ff445907a016b1fc3051a4d01d211a8653931ab521dd125ec0238621e0c25afb4301203c3a55409491a010d0567df02ca24df650b4c7e4d09ac6523b872dd20256530c540851dc7051be913a50157053644e51524cd05b4b577ad01190552d2cfdd13ae85081579a511b28518160ddd27e105ddc1f59d0336a53c157e642c95450c3e4b5409b6855b36389c19ed653df02124032c852081066c012505e2e7d264013d259c4258c40163058419530c8918281846182a183f183f184d182a184618311904c0a16576797065728300030a0027
Deployed Bytecode
0xfe71006157ac515034610969576020615ca16000396000516020602082615ca10160003960005111610969576020602082615ca101600039600051018082615ca10160803950506020615cc1600039600051600a602082615ca10160003960005111610969576020602082615ca101600039600051018082615ca10160c03950506020615d616000396000518060a01c61096957610100526020615d816000396000518060a01c61096957610120526020615da16000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561011b57905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b61016001526001018181186100ea575b5050806101405250506020615dc16000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561019457905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b6102800152600101818118610163575b5050806102605250506020615de16000396000516008602082615ca1016000396000511161096957602081615ca10160003960005160208160051b018083615ca101610380395050506020615e016000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561024d57905b60208160051b6020860101615ca1016000396000518060081c610969578160051b6104c0015260010181811861021c575b5050806104a05250506020615e216000396000516008602082615ca1016000396000511161096957602081615ca101600039600051600081600881116109695780156102c657905b60208160051b6020860101615ca1016000396000518060201b610969578160051b6105e00152600101818118610295575b5050806105c05250506020615e416000396000516008602082615ca1016000396000511161096957602081615ca1016000396000516000816008811161096957801561033f57905b60208160051b6020860101615ca1016000396000518060a01c610969578160051b610700015260010181811861030e575b5050806106e0525050610120515a6004610800527f9c4258c4000000000000000000000000000000000000000000000000000000006108205261080050600060006108005161082060008686f19050905061532c5261532c516103a85760036102605111610969575b6101005161548c526101205161530c526102605160208160051b01600081601f0160051c600981116109695780156103fc57905b8060051b61026001518160051b60600161530c01526001018181186103dc575b505050506102605161534c526101405160208160051b01600081601f0160051c6009811161096957801561044d57905b8060051b61014001518160051b6101c00161530c015260010181811861042c575b505050506104a0511561096957600060051b6104c001516155ec5260026155ec511461560c52610380511561096957600060051b6103a0015161562c5260006008905b806108005261534c5161080051101561054a5761080051610260518110156109695760051b610280015163095ea7b36108205261530c51610840527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610860526020610820604461083c6000855af161050e573d600060003e3d6000fd5b3d61052557803b156109695760016108805261053e565b60203d1061096957610820518060011c61096957610880525b61088090505115610969575b60010181811861049057505060036155ec511861068357610140511561096957600060051b610160015163313ce567610800526020610800600461081c845afa610599573d600060003e3d6000fd5b60203d1061096957610800518060081c6109695761084052610840905051604d81116109695780600a0a905061566c52610140511561096957600060051b61016001516338d52e0f610800526020610800600461081c845afa610601573d600060003e3d6000fd5b60203d1061096957610800518060a01c610969576108405261084090505163313ce567610860526020610860600461087c845afa610644573d600060003e3d6000fd5b60203d1061096957610860518060081c610969576108a0526108a09050518060120360128111610969579050604d81116109695780600a0a905061568c525b336154ac5260646020615ce1600039600051026108005261080051600555610800516006556020615d016000396000516003556020615d216000396000516004556020615d4160003960005115610969576020615d4160003960005160145561f37460155542604052426060526106fb610820610928565b61082051601655670de0b6b3a7640000604052670de0b6b3a7640000606052610725610820610928565b610820516012556000600a556000600b556002600955600060015560006002556106e0511561096957600060051b61070001516105c0511561096957600060051b6105e001518060e01c90508060e01b818160e01c186109695790501761564c52602060805101600081601f0160051c600281116109695780156107c557905b8060051b608001518160051b6103a00161530c01526001018181186107a5575b505050602060c05101600081601f0160051c6002811161096957801561080757905b8060051b60c001518160051b6104000161530c01526001018181186107e7575b50505060206156ac5101600081601f0160051c6003811161096957801561084b57905b8060051b6103a00161530c01518160051b610820015260010181811861082a575b50505061082080516020820120905061574c52600143034061578c524661576c527fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564726108405261574c51610860527f1c54f243822e0e9a0a377610b81577e771b3efe79964e76636b0d5d10247950d61088052466108a052306108c05261578c516108e05260c0610820526108208051602082012090506157ac523360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6000610820526020610820a361530c61096e610000396157cc610000f35b6fffffffffffffffffffffffffffffffff60405111610969576fffffffffffffffffffffffffffffffff606051116109695760605160801b60405117815250565b600080fd60003560e01c60056005600783160261510801601b39600051600760078260ff16848460181c0260181c06028260081c61ffff160160193950600051818160181c14600336111661004f57612ff5565b8060fe16361034826001160217615103578060081c61ffff16565b600260405260206040f35b602061530c60403960206040f35b602061534c60403960206040f35b6020600435602061536c6000396000518110156151035760051b60800161530c0160403960206040f35b602060043560206154cc6000396000518110156151035760051b6101e00161530c0160403960206040f35b60035460405260206040f35b60045460405260206040f35b64012a05f20060405260206040f35b60055460405260206040f35b60065460405260206040f35b60075460405260206040f35b60085460405260206040f35b60043560095481101561510357600a015460405260206040f35b60145460405260206040f35b60155460405260206040f35b60165460405260206040f35b60208060405280604001602060206156ac60003960005101806156ac8339508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b602080604052806040016020602061570c600039600051018061570c8339508051806020830101601f82600003163682375050601f19601f825160200101169050810190506040f35b601260405260206040f35b60208060805260066040527f76372e302e30000000000000000000000000000000000000000000000000000060605260408160800181518152602082015160208201528051806020830101601f82600003163682375050601f19601f8251602001011690509050810190506080f35b6004358060a01c61510357604052601760405160205260005260406000205460605260206060f35b6004358060a01c615103576040526024358060a01c615103576060526018604051602052600052604060002080606051602052600052604060002090505460805260206080f35b6004358060a01c61510357604052601a60405160205260005260406000205460605260206060f35b602061578c60403960206040f35b33610a2052610346565b6084358060a01c61510357610a20525b60043580600f0b8118615103576109e05260243580600f0b811861510357610a0052600054600214615103576002600055602033610760526109e05161078052610a00516107a052604060446107c037610a2051610800526000610820526103af610a406144c4565b610a406003600055f35b33610a20526103d3565b6084358060a01c61510357610a20525b60043580600f0b8118615103576109e05260243580600f0b811861510357610a0052600054600214615103576002600055602061560c60003960005161510357602033610760526109e05161078052610a00516107a052604060446107c037610a20516108005260016108205261044b610a406144c4565b610a406003600055f35b336107a05261046f565b6084358060a01c615103576107a0525b60043580600f0b8118615103576107605260243580600f0b811861510357610780526000546002146151035760026000556107a05115615103576104b4610800613752565b61080060406107c060408360045afa50506104d061084061396e565b610840604061080060408360045afa50506040604060406107c060045afa5060406080604061080060045afa50610508610880613acb565b610880604061084060408360045afa505060e036610880376001610760511261054a57610760516001810380600f0b81186151035790506108a05260016108e0525b6107805161057a57602060206154cc6000396000511561510357600060051b6101e00161530c01610940396105bf565b610780516001810380600f0b81186151035790506108c05260016109005260206108c051602061536c6000396000518110156151035760051b60800161530c01610940395b6108e051610320526108a0516103405260443561036052336103805260006103a05260016107605112156105f45760006105fd565b60016107805112155b6103c05261060c61098061331f565b610980516109605261076051610623576001610629565b61078051155b61071d57610940516370a0823161098052306109a0526020610980602461099c845afa61065b573d600060003e3d6000fd5b60203d106151035761098090505161088052602061530c600039600051633df02124610980526108a0516109a0526108c0516109c052610960516109e052606435610a0052803b15615103576000610980608461099c6000855af16106c5573d600060003e3d6000fd5b50610940516370a0823161098052306109a0526020610980602461099c845afa6106f4573d600060003e3d6000fd5b60203d1061510357610980905051610880518082038281116151035790509050610880526108e3565b6108e051600181116151035760051b6108400151670de0b6b3a7640000610960516108e051600181116151035760051b6107c00151808202811583838304141715615103579050905004808201828110615103579050905061092052610920516102e0526040610300604061084060045afa50604061034060406107c060045afa506108e05161038052610900516103a0526107ba6109806140fc565b61098051610880526109005160018111615103576001018054610880518082038281116151035790509050815550600161078051126108d657610940516370a082316109a052306109c05260206109a060246109bc845afa610821573d600060003e3d6000fd5b60203d10615103576109a090505161098052602061530c600039600051631a4d01d26109a052610880516109c0526108c0516109e0526000610a0052803b156151035760006109a060646109bc6000855af1610882573d600060003e3d6000fd5b50610940516370a082316109a052306109c05260206109a060246109bc845afa6108b1573d600060003e3d6000fd5b60203d10615103576109a0905051610980518082038281116151035790509050610880525b6064356108805110615103575b6109405163a9059cbb610980526107a0516109a052610880516109c0526020610980604461099c6000855af161091e573d600060003e3d6000fd5b3d61093557803b156151035760016109e05261094e565b60203d1061510357610980518060011c615103576109e0525b6109e09050511561510357337fd013ca23e77a65003c2c659c5442c00c805371b7fc1ebd4c206c41d1536bd90b61076051610980526044356109a052610780516109c052610880516109e0526080610980a260206108806003600055f35b336104e0526109c6565b6064358060a01c615103576104e0525b6000546002146151035760026000556104e05115615103576109e9610520613b4e565b61052051610500526109fc61056061396e565b610560604061052060408360045afa5050610a186105a0613752565b6105a0604061056060408360045afa50506040610120604061056060045afa506040610160604061052060045afa50610500516101a052610a5a6105c0614754565b6105c0516105a0526019546105c05260406105e0604061052060045afa5060006002905b806106205261062051600181116151035760051b6004013515610b255761062051600181116151035760051b6105e001805161062051610320527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6103405261062051600181116151035760051b600401356103605233610380526040366103a037610b0b61064061331f565b610640518082018281106151035790509050815250610b2f565b6105c05115615103575b600101818118610a7e5750506040610120604061056060045afa50604061016060406105e060045afa50610500516101a052610b6c610640614754565b61064051610620526105a05161062051111561510357606036610640376105c05115610f13576060366106a0376105a05161062051808201828110615103579050905060011c610700526040366107203760035460011b60021c6107605260006002905b80610780526106205161078051600181116151035760051b610520015180820281158383830414171561510357905090506105a051801561510357808204905090506106a05261078051600181116151035760051b6105e001516106e0526106e0516106a05111610c4d576106a0516106e051036106c052610c5b565b6106e0516106a051036106c0525b670de0b6b3a764000061078051600181116151035760051b610560015161078051600181116151035760051b61052001516106e051808201828110615103579050905080820281158383830414171561510357905090500461072052610720516040526107005160605261076051608052610cd76107a0613c59565b6107a051610740526402540be400610740516106c05180820281158383830414171561510357905090500461078051600181116151035760051b61064001526107805160095481101561510357600a0180546402540be40061078051600181116151035760051b610640015164012a05f20081028164012a05f20082041861510357905004808201828110615103579050905081555061078051600181116151035760051b6105e001805161078051600181116151035760051b61064001518082038281116151035790509050815250600101818118610bd057505060406040604061056060045afa506040608060406105e060045afa50610dda6107c0613acb565b6107c0604061078060408360045afa5050602061548c6000396000516350e7277d6107c0526060806107e052806107e001600061078051610980526107a0516109a0526002610960526000610960518084528060051b60008260088111615103578015610e6157905b8060051b61098001518160051b602089010152600101818118610e43575b50508201602001915050905090508101905061050051610800526002610820525060206107c06101846107dc845afa610e9f573d600060003e3d6000fd5b60203d10615103576107c0905051610620526105a0516105c051610620516105a0518082038281116151035790509050808202811583838304141715615103579050905004610680526040610140604061078060045afa506105005161018052610620516101a052610f8e613f6856610f8e565b61062051610680526106205160405261062051606052610f346106a0612ffb565b6106a051601355601654604052610f4c6106e0613d19565b6106e060406106a060408360045afa5050426106c0511015610f8e57426106c0526106a0516040526106c051606052610f866106e0612ffb565b6106e0516016555b6044356106805110156110015760146106a0527f536c697070616765207363726577656420796f750000000000000000000000006106c0526106a0506106a051806106c001601f826000031636823750506308c379a061066052602061068052601f19601f6106a051011660440161067cfd5b6105c0516106805180820182811061510357905090506105c05260176104e0516020526000526040600020546106a052610680516106a0510160176104e0516020526000526040600020556105c0516019556104e05160007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef610680516106c05260206106c0a3337f189c623b666b1b45b83d7178f39b8c087cb09774317ca2f53c2d3c3726f222a26080806106c052806106c0016000604060046109a0376002610980526000610980518084528060051b6000826008811161510357801561110457905b8060051b6109a001518160051b6020890101526001018181186110e6575b505082016020019150509050905081019050806106e052806106c001600061064051610ac05261066051610ae0526002610aa0526000610aa0518084528060051b6000826008811161510357801561117657905b8060051b610ac001518160051b602089010152600101818118611158575b50508201602001915050905090508101905061062051610700526105c051610720526106c0a260206106806003600055f35b336107a0526111c2565b6064358060a01c615103576107a0525b60243580600f0b81186151035761078052600054600214615103576002600055600435156151035760c0366107c03760043561020052610780516102205261120b610880614853565b61088080516107c05260208101516107e05260408101604061080060408360045afa505060808101516108405260a081015161086052506044356107c05110156112b5576018610880527f4e6f7420656e6f75676820636f696e732072656d6f76656400000000000000006108a0526108805061088051806108a001601f826000031636823750506308c379a061084052602061086052601f19601f61088051011660440161085cfd5b6107805160095481101561510357600a0180546402540be4006107e05164012a05f20081028164012a05f2008204186151035790500480820182811061510357905090508155503360405260043560605261130e614e6a565b610780516040526107c0516060526107a05160805261132b613569565b337f6f48129db1f37ccb9cc5dd7e119cb32750cabdf75b48375d730d26ce3659bbe161078051610880526004356108a0526107c0516108c0526019546108e0526080610880a26040610140604061080060045afa506108405161018052610860516101a052611398613f68565b60206107c06003600055f35b336104c0526113be565b6064358060a01c615103576104c0525b6000546002146151035760026000556113d8610500613b4e565b610500516104e0526113eb610540613752565b610540604061050060408360045afa505061140761058061396e565b610580604061054060408360045afa50506040610120604061050060045afa506040610160604061054060045afa506104e0516101a0526114496105a0614754565b6105a0516105805260406105a0604061054060045afa5060006002905b806105e0526105e051600181116151035760051b60040135156114e8576105e051600181116151035760051b6105a00180516105e051600181116151035760051b6004013580820382811161510357905090508152506105e0516040526105e051600181116151035760051b600401356060526104c0516080526114e8613569565b6001018181186114665750506040610120604061050060045afa50604061016060406105a060045afa506104e0516101a052611525610600614754565b610600516105e05260035460011b60021c61060052610580516105e051808201828110615103579050905060011c6106205260e0366106403760006002905b80610720526105e05161072051600181116151035760051b6105400151808202811583838304141715615103579050905061058051801561510357808204905090506106c05261072051600181116151035760051b6105a0015161070052610700516106c051116115e1576106c05161070051036106e0526115ef565b610700516106c051036106e0525b670de0b6b3a764000061072051600181116151035760051b610500015161072051600181116151035760051b61054001516107005180820182811061510357905090508082028115838383041417156151035790509050046106a0526106a051604052610620516060526106005160805261166b610740613c59565b61074051610680526402540be400610680516106e05180820281158383830414171561510357905090500461072051600181116151035760051b61064001526107205160095481101561510357600a0180546402540be40061072051600181116151035760051b610640015164012a05f20081028164012a05f20082041861510357905004808201828110615103579050905081555061072051600181116151035760051b6105a001805161072051600181116151035760051b610640015180820382811161510357905090508152506001018181186115645750506040610120604061050060045afa50604061016060406105a060045afa506104e0516101a052611778610720614754565b610720516105e05260406040604061050060045afa506040608060406105a060045afa506117a7610720613acb565b610720604061076060408360045afa50506104e0516107a0526105e0516107c0526080610140608061076060045afa506117df613f68565b6019546107205261058051610580516105e051808203828111615103579050905061072051808202811583838304141715615103579050905004600181018181106151035790506107405260026107405110615103576044356107405111156118a8576014610760527f536c697070616765207363726577656420796f750000000000000000000000006107805261076050610760518061078001601f826000031636823750506308c379a061072052602061074052601f19601f61076051011660440161073cfd5b33604052610740516060526118bb614e6a565b337f3631c28b1f9dd213e0319fb167b554d76b6c283a41143eb400a0d1adb1af1755608080610760528061076001600060406004610a40376002610a20526000610a20518084528060051b6000826008811161510357801561193757905b8060051b610a4001518160051b602089010152600101818118611919575b50508201602001915050905090508101905080610780528061076001600061064051610b605261066051610b80526002610b40526000610b40518084528060051b600082600881116151035780156119a957905b8060051b610b6001518160051b60208901015260010181811861198b575b5050820160200191505090509050810190506105e0516107a052610720516107405180820382811161510357905090506107c052610760a260206107406003600055f35b336102a05260016102c052611a36565b6064358060a01c615103576102a05260016102c052611a36565b6064358060a01c615103576102a0526084358060011c615103576102c0525b6000546002146151035760026000556019546102e052600435156151035760403661030037611a6661038061396e565b610380604061034060408360045afa505060006103805260006002905b806103a0526102e0516103a051600181116151035760051b6103400151600435808202811583838304141715615103579050905004610380526103a051600181116151035760051b60240135610380511015611b645760306103c0527f5769746864726177616c20726573756c74656420696e20666577657220636f696103e0527f6e73207468616e20657870656374656400000000000000000000000000000000610400526103c0506103c051806103e001601f826000031636823750506308c379a06103805260206103a052601f19601f6103c051011660440161039cfd5b610380516103a051600181116151035760051b61030001526103a051604052610380516060526102a051608052611b99613569565b600101818118611a8357505033604052600435606052611bb7614e6a565b601654604052611bc86103e0613d19565b6103e060406103a060408360045afa50506013546103e0526fffffffffffffffffffffffffffffffff6103e0511661040052610400516102e051610400516004358082028115838383041417156151035790509050048082038281116151035790509050610460526103e0516040526015546060526103c051608052611c4f610420613e3a565b610420516104805260406040604061046060045afa50611c70610440612ffb565b61044051601355426103c0511015611ca857426103c0526103a0516040526103c051606052611ca0610420612ffb565b610420516016555b337f347ad828e58cbe534d8f6b67985d791360756b18f0d95fd9f197a66cc46480ea6060806104205280610420016000610300516106e052610320516107005260026106c05260006106c0518084528060051b60008260088111615103578015611d2c57905b8060051b6106e001518160051b602089010152600101818118611d0e575b5050820160200191505090509050810190508061044052806104200160006000825260006000600060088111615103578015611d7b57905b60008160051b602087010152600101818118611d64575b5050810160200190509050810190506004356102e0510361046052610420a26102c05115611dab57611dab614eda565b6103005161042052610320516104405260406104206003600055f35b611dcf614eda565b005b600435615103576fffffffffffffffffffffffffffffffff6012541660405260206040f35b6004356151035760125460801c60405260206040f35b60043561510357611e1e610220613b4e565b6102205161020052611e31610260613752565b610260604061032060408360045afa5050611e4d6102a061396e565b6102a0604061036060408360045afa505060806040608061032060045afa50611e776102e0613acb565b6102e0604061022060408360045afa5050602061548c6000396000516350e7277d610280526060806102a052806102a0016000610220516104405261024051610460526002610420526000610420518084528060051b60008260088111615103578015611efe57905b8060051b61044001518160051b602089010152600101818118611ee0575b505082016020019150509050905081019050610200516102c05260026102e05250602061028061018461029c845afa611f3c573d600060003e3d6000fd5b60203d106151035761028090505161026052602060406040604061022060045afa50610200516080526102605160a052611f77610280613d3e565b610280f35b600054600214615103576004356151035760206012546040526014546060526fffffffffffffffffffffffffffffffff60165416608052611fbe610140613e3a565b610140f35b60005460021461510357602060135460405260155460605260165460801c608052611fef610140613e3a565b610140f35b6004358060a01c6151035760c0523360405260c05160605260243560805261201a615083565b600160e052602060e0f35b6004358060a01c6151035760c0526024358060a01c6151035760e05260c05160405260e05160605260443560805261205b615083565b601860c051602052600052604060002080336020526000526040600020905054610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100511461211a576101005160443580820382811161510357905090506101205261012051601860c0516020526000526040600020803360205260005260406000209050553360c0517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92561012051610140526020610140a35b6001610120526020610120f35b6004358060a01c615103576040526024356018336020526000526040600020806040516020526000526040600020905055604051337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560243560605260206060a3600160605260206060f35b6004358060a01c61510357610120526024358060a01c61510357610140526084358060081c6151035761016052610120511561510357606435421161510357601a6101205160205260005260406000205461018052600060026101c0527f19010000000000000000000000000000000000000000000000000000000000006101e0526101c080516020820183610320018151815250508083019250505061223b610200614fee565b610200518161032001526020810190507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961024052610120516102605261014051610280526044356102a052610180516102c0526064356102e05260c061022052610220805160208201209050816103200152602081019050806103005261030090508051602082012090506101a052610120513b15612409576000604060a46102603760406102405261024080516020820183610320018281848460045afa50505080830192505050610160516102a0526102a0601f810180516102e0525060016102c0526102c09050805160208201836103200181518152505080830192505050806103005261030090506020815101806101c0828460045afa5050507f1626ba7e0000000000000000000000000000000000000000000000000000000061012051631626ba7e6102405260406101a051610260528061028052806102600160206101c051018082826101c060045afa50508051806020830101601f82600003163682375050601f19601f82516020010116905081015050602061024060c461025c845afa6123f1573d600060003e3d6000fd5b60203d1061510357610240905051186151035761244a565b610120516000610240526101a0516101c052610160516101e05260a4356102005260c43561022052602061024060806101c060015afa506102405118615103575b60443560186101205160205260005260406000208061014051602052600052604060002090505560016101805101601a6101205160205260005260406000205561014051610120517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256044356101c05260206101c0a360016101c05260206101c0f35b60206124da610120614fee565b610120f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa61252e573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c09050516383aa796a60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa612585573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa6125e2573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163d6fc10ab60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa612639573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa612696573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c0905051630c601c2c60e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa6126ed573d600060003e3d6000fd5b60203d106151035760e09050f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa61274a573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163c02c60a660e0526040516101005260605161012052604435610140523061016052602060e0608460fc845afa6127a1573d600060003e3d6000fd5b60203d106151035760e09050f35b60243580600f0b8118615103576107805260206004356102005261078051610220526127dc6107a0614853565b6107a0f35b6000546002146151035760195460405260206040f35b6000546002146151035761280c610240613752565b610240604061030060408360045afa505061282861028061396e565b610280604061034060408360045afa505060806040608061030060045afa506128526102c0613acb565b6102c0604061020060408360045afa5050602061548c6000396000516350e7277d610280526060806102a052806102a0016000610200516104405261022051610460526002610420526000610420518084528060051b600082600881116151035780156128d957905b8060051b61044001518160051b6020890101526001018181186128bb575b5050820160200191505090509050810190506128f6610260613b4e565b610260516102c05260026102e05250602061028061018461029c845afa612922573d600060003e3d6000fd5b60203d10615103576102809050516102405261024051670de0b6b3a7640000810281670de0b6b3a764000082041861510357905060195480156151035780820490509050610260526020610260f35b6044358060011c61510357604052602060206154ac60003960005163e31593d8606052602060606004607c845afa6129ae573d600060003e3d6000fd5b60203d10615103576060518060a01c6151035760a05260a090505163fb79eb2760c05260608060e0528060e001600060406004610280376002610260526000610260518084528060051b60008260088111615103578015612a2957905b8060051b61028001518160051b602089010152600101818118612a0b575b50508201602001915050905090508101905060405161010052306101205250602060c061018460dc845afa612a63573d600060003e3d6000fd5b60203d106151035760c09050f35b6064612a7d60c0613b4e565b60c0510460e052602060e0f35b6020612a9660c0613b4e565b60c0f35b6020612aa761020061396e565b610200600435600181116151035760051b81019050f35b612ac961024061396e565b610240604061020060408360045afa50506020806102405280610240016000610200516103a052610220516103c0526002610380526000610380518084528060051b60008260088111615103578015612b3c57905b8060051b6103a001518160051b602089010152600101818118612b1e575b505082016020019150509050905081019050610240f35b612b5e610180613752565b610180604061014060408360045afa50506020806101805280610180016000610140516102e052610160516103005260026102c05260006102c0518084528060051b60008260088111615103578015612bd157905b8060051b6102e001518160051b602089010152600101818118612bb3575b505082016020019150509050905081019050610180f35b60043580600f0b81186151035760405260243580600f0b811861510357606052602060206154ac60003960005163e31593d8608052602060806004609c845afa612c37573d600060003e3d6000fd5b60203d10615103576080518060a01c6151035760c05260c090505163a63530bd60e05260405161010052606051610120523061014052602060e0606460fc845afa612c87573d600060003e3d6000fd5b60203d106151035760e09050f35b60206154ac60003960005163f851a44060c052602060c0600460dc845afa612cc2573d600060003e3d6000fd5b60203d106151035760c0518060a01c6151035761010052610100905051331861510357600754620151808101818110615103579050421061510357426201518081018181106151035790506024351061510357612d1f60e0613b4e565b60e05160c0526004356064810281606482041861510357905060e05260043515612d5157620f423f6004351115612d54565b60005b156151035760c05160e05110612d845760c051600a810281600a82041861510357905060e0511161510357612da0565b60c05160e051600a810281600a82041861510357905010615103575b60c05160055560e051600655426007556024356008557fa2b71ec6df949300b59aab36b55e189697b750119dd349fcfa8c0f779e83c25460c0516101005260e051610120524261014052602435610160526080610100a1005b60206154ac60003960005163f851a44060c052602060c0600460dc845afa612e26573d600060003e3d6000fd5b60203d106151035760c0518060a01c6151035761010052610100905051331861510357612e5360e0613b4e565b60e05160c05260c05160055560c05160065542600755426008557f46e22fb3709ad289f62ce63d469248536dbc78d82b84a3d7e74ad606dc20193860c05160e0524261010052604060e0a1005b60206154ac60003960005163f851a440604052602060406004605c845afa612ecd573d600060003e3d6000fd5b60203d10615103576040518060a01c61510357608052608090505133186151035764012a05f20060043511615103576004356003556802b5e3af16b1880000602435600435808202811583838304141715615103579050905011615103576024356004557f750d10a7f37466ce785ee6bcb604aac543358db42afbcc332a3c12a49c80bf6d6040600460403760406040a1005b60206154ac60003960005163f851a440604052602060406004605c845afa612f8d573d600060003e3d6000fd5b60203d10615103576040518060a01c6151035760805260809050513318615103576024356004350215615103576004356014556024356015557f68dc4e067dff1862b896b7a0faf55f97df1a60d0aaa79481b69d675f2026a28c6040600460403760406040a1005b60006000fd5b6fffffffffffffffffffffffffffffffff60405111615103576fffffffffffffffffffffffffffffffff606051116151035760605160801b60405117815250565b602061532c6000396000511561317d5760006080526000602061534c600039600051600881116151035780156130d357905b806101a05260605160008112615103576101a051186130aa5760805160078111615103576040518160051b60a0015260018101608052506130c8565b608051600781116151035760008160051b60a0015260018101608052505b60010181811861306e575b5050602061530c60003960005163b72df5de6101a0526040806101c052806101c00160006080518083528060051b6000826008811161510357801561313157905b8060051b60a001518160051b602088010152600101818118613114575b5050820160200191505090508101905060006101e0525060206101a06101646101bc6000855af1613167573d600060003e3d6000fd5b60203d10615103576101a090505181525061331d565b6020600260206154cc6000396000511061510357600160051b6101e00161530c016080396080516370a0823160c0523060e052602060c0602460dc845afa6131ca573d600060003e3d6000fd5b60203d106151035760c090505160a0526002602061534c600039600051186132565760403660c037604051606051600181116151035760051b60c00152602061530c600039600051630b4c7e4d610100526040610120604060c060045afa50600061016052803b15615103576000610100606461011c6000855af1613254573d600060003e3d6000fd5b505b6003602061534c600039600051186132d25760603660c037604051606051600281116151035760051b60c00152602061530c600039600051634515cef3610120526060610140606060c060045afa5060006101a052803b15615103576000610120608461013c6000855af16132d0573d600060003e3d6000fd5b505b6080516370a0823160c0523060e052602060c0602460dc845afa6132fb573d600060003e3d6000fd5b60203d106151035760c090505160a05180820382811161510357905090508152505b565b60206103205160206154cc6000396000518110156151035760051b6101e00161530c016103e039600061040052600061034051121561335f576000613368565b60016103205118155b1561339a57602061034051602061536c6000396000518110156151035760051b60800161530c016103e0396001610400525b6103e0516370a082316104405230610460526020610440602461045c845afa6133c8573d600060003e3d6000fd5b60203d1061510357610440905051610420526103a0516134bd576103605115615103576103e0516323b872dd6104405261038051610460523061048052610360516104a0526020610440606461045c6000855af161342b573d600060003e3d6000fd5b3d61344257803b156151035760016104c05261345b565b60203d1061510357610440518060011c615103576104c0525b6104c090505115615103576103e0516370a082316104405230610460526020610440602461045c845afa613494573d600060003e3d6000fd5b60203d1061510357610440905051610420518082038281116151035790509050610420526134f9565b610400516134f9576104205161032051600181116151035760010154808203828111615103579050905061042052610360516104205110615103575b6104005115613539576103c051156135175761042051815250613567565b610420516040526103405160605261353061044061303c565b61044051610420525b6103205160018111615103576001018054610420518082018281106151035790509050815550610420518152505b565b6080511561510357602061560c60003960005161363b57604051600181116151035760010180546060518082038281116151035790509050815550602060405160206154cc6000396000518110156151035760051b6101e00161530c0160003960005163a9059cbb60a05260805160c05260605160e052602060a0604460bc6000855af16135fc573d600060003e3d6000fd5b3d61361357803b156151035760016101005261362b565b60203d106151035760a0518060011c61510357610100525b6101009050511561510357613750565b602060405160206154cc6000396000518110156151035760051b6101e00161530c016000396000516370a0823160c0523060e052602060c0602460dc845afa613689573d600060003e3d6000fd5b60203d106151035760c090505160a052602060405160206154cc6000396000518110156151035760051b6101e00161530c0160003960005163a9059cbb60c05260805160e05260605161010052602060c0604460dc6000855af16136f2573d600060003e3d6000fd5b3d61370957803b1561510357600161012052613721565b60203d106151035760c0518060011c61510357610120525b610120905051156151035760a05160605180820382811161510357905090506040516001811161510357600101555b565b602061562c604039602061530c60003960005163bb7b8b80608052602060806004609c845afa613787573d600060003e3d6000fd5b60203d10615103576080905051606052600160206155ec600039600051186137bb57602061564c60003960005115156137be565b60005b61387857600360206155ec6000396000511861395f57670de0b6b3a7640000604051602060206154cc6000396000511561510357600060051b6101e00161530c016000396000516307a2d13a608052602061566c60a039602060806024609c845afa61382f573d600060003e3d6000fd5b60203d106151035760809050518082028115838383041417156151035790509050602061568c60003960005180820281158383830414171561510357905090500460405261395f565b602061564c60003960005173ffffffffffffffffffffffffffffffffffffffff811690508060a01c615103575a7fffffffff00000000000000000000000000000000000000000000000000000000602061564c6000396000511660e052602060c05260c050602061012060c05160e08585fa905090506138fd573d600060003e3d6000fd5b3d602081183d6020100218610100526101008051608052602081015160a052506020608051186151035760a05160805160200360031b1c60c052670de0b6b3a764000060405160c0518082028115838383041417156151035790509050046040525b6040816040604060045afa5050565b60403660403760095460208160051b01600081601f0160051c600981116151035780156139af57905b80600901548160051b60800152600101818118613997575b5050505060006002905b806101a052602061560c600039600051613a18576101a0516001811161510357600101546101a0516080518110156151035760051b60a0015180820382811161510357905090506101a051600181116151035760051b60400152613ab0565b60206101a05160206154cc6000396000518110156151035760051b6101e00161530c016000396000516370a082316101c052306101e05260206101c060246101dc845afa613a6b573d600060003e3d6000fd5b60203d10615103576101c09050516101a0516080518110156151035760051b60a0015180820382811161510357905090506101a051600181116151035760051b604001525b6001018181186139b95750506040816040604060045afa5050565b60403660c03760006002905b8061010052670de0b6b3a764000061010051600181116151035760051b6040015161010051600181116151035760051b6080015180820281158383830414171561510357905090500461010051600181116151035760051b60c00152600101818118613ad7575050604081604060c060045afa5050565b6008546040526006546060526040514210613b7257606051815250613c5756613c57565b60055460805260075460a05260805160605111613bf457608051606051608051034260a0518082038281116151035790509050808202811583838304141715615103579050905060405160a0518082038281116151035790509050801561510357808204905090508082038281116151035790509050815250613c5756613c57565b608051608051606051034260a0518082038281116151035790509050808202811583838304141715615103579050905060405160a05180820382811161510357905090508015615103578082049050905080820182811061510357905090508152505b565b60045460a0526402540be40060a05111613c7857608051815250613d17565b60405160605180820182811061510357905090506fffffffffffffffffffffffffffffffff8111615103576002810a905060c0526402540be4006402540be40060a051038060021b818160021c186151035790506040518082028115838383041417156151035790509050606051808202811583838304141715615103579050905060c051801561510357808204905090500160805160a05102048152505b565b6fffffffffffffffffffffffffffffffff60405116815260405160801c602082015250565b60805160011b60c05260a05160021c60e05260006002905b806101005260e05160a051808202811583838304141715615103579050905061010051600181116151035760051b604001518015615103578082049050905060e052600101818118613d56575050606460c051604051808202811583838304141715615103579050905004610100526101005160605160e0516040518082028115838383041417156151035790509050048082018281106151035790509050670de0b6b3a7640000810281670de0b6b3a76400008204186151035790506101005160e051808201828110615103579050905080156151035780820490509050815250565b6fffffffffffffffffffffffffffffffff6040511660a05260405160801c60c052426080511015613f5f57602061548c60003960005163e46751e361010052606051670de0b6b3a7640000608051420302048060ff1c615103577f8000000000000000000000000000000000000000000000000000000000000000811461510357600003610120526020610100602461011c845afa613ede573d600060003e3d6000fd5b60203d106151035761010090505160e052670de0b6b3a764000060a05160e05180670de0b6b3a764000003670de0b6b3a76400008111615103579050808202811583838304141715615103579050905060c05160e0518082028115838383041417156151035790509050808201828110615103579050905004815250613f66565b60c0518152505b565b601654604052613f79610200613d19565b61020060406101c060408360045afa505060125461020052610200516102205260406040604061014060045afa50610180516080526101a05160a052613fc0610260613d3e565b6102605161024052610240511561403d5761024051671bc16d674ec80000818118671bc16d674ec800008310021890506102a052610200516040526014546060526101c051608052614013610260613e3a565b610260516102c0526040604060406102a060045afa50614034610280612ffb565b61028051610220525b610220516012556101a0516102a0526013546040526015546060526101e05160805261406a610260613e3a565b610260516102c0526040604060406102a060045afa5061408b610280612ffb565b6102805160135560006002905b80610260524261026051600181116151035760051b6101c0015110156140ce574261026051600181116151035760051b6101c001525b6001018181186140985750506101c0516040526101e0516060526140f3610260612ffb565b61026051601655565b6141076103e0613b4e565b6103e0516103c052602061548c6000396000516350e7277d610400526060806104205280610420016000610300516105c052610320516105e05260026105a05260006105a0518084528060051b6000826008811161510357801561418557905b8060051b6105c001518160051b602089010152600101818118614167575b5050820160200191505090509050810190506103c0516104405260026104605250602061040061018461041c845afa6141c3573d600060003e3d6000fd5b60203d10615103576104009050516103e052602061548c60003960005163aa3ded9b6104205260e061038051610440526103a051610460526102e05161048052806104a05280610440016000610300516106605261032051610680526002610640526000610640518084528060051b6000826008811161510357801561426357905b8060051b61066001518160051b602089010152600101818118614245575b5050820160200191505090509050810190506103c0516104c0526103e0516104e05260026105005250602061042061020461043c845afa6142a9573d600060003e3d6000fd5b60203d1061510357610420905051610400526103a051600181116151035760051b610300015161040051808203828111615103579050905060018103818111615103579050610420526402540be4006104205161038051600181116151035760051b61030001516102e051808201828110615103579050905060011c6040526103a051600181116151035760051b610300015161040051808201828110615103579050905060011c606052600354608052614365610460613c59565b610460518082028115838383041417156151035790509050046104405261042051610440518082038281116151035790509050670de0b6b3a7640000810281670de0b6b3a76400008204186151035790506103a051600181116151035760051b610340015180156151035780820490509050610420526103a05160095481101561510357600a0180546103a051600181116151035760051b61034001516402540be4006104405164012a05f20081028164012a05f20082041861510357905004670de0b6b3a7640000810281670de0b6b3a76400008204186151035790500480820182811061510357905090508155506040610460604061030060045afa506102e05161038051600181116151035760051b6104600152610400516103a051600181116151035760051b61046001526040610140604061046060045afa506103c051610180526103e0516101a0526144bb613f68565b61042051815250565b6107a0516107805114615103576107c05115615103576144e5610880613752565b610880604061084060408360045afa50506145016108c061396e565b6108c0604061088060408360045afa505060406040604061084060045afa5060406080604061088060045afa50614539610900613acb565b61090060406108c060408360045afa505061078051610320527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610340526107c051610360526107605161038052610820516103a05260006103c0526145a061092061331f565b610920516109005261078051600181116151035760051b6108c00151670de0b6b3a76400006109005161078051600181116151035760051b6108400151808202811583838304141715615103579050905004808201828110615103579050905061092052610920516102e052604061030060406108c060045afa506040610340604061084060045afa5061078051610380526107a0516103a0526146456109606140fc565b61096051610940526107e0516109405110156146e657602e610960527f45786368616e676520726573756c74656420696e20666577657220636f696e73610980527f207468616e2065787065637465640000000000000000000000000000000000006109a05261096050610960518061098001601f826000031636823750506308c379a061092052602061094052601f19601f61096051011660440161093cfd5b6107a0516040526109405160605261080051608052614703613569565b337f8b3e96f2b889fa771c53c981b40daf005f63f637f1869f707052d15a3dd97140610780516109605261090051610980526107a0516109a052610940516109c0526080610960a261094051815250565b60406040604061012060045afa5060406080604061016060045afa5061477b610200613acb565b61020060406101c060408360045afa5050602061548c6000396000516350e7277d6102005260608061022052806102200160006101c0516103c0526101e0516103e05260026103a05260006103a0518084528060051b6000826008811161510357801561480257905b8060051b6103c001518160051b6020890101526001018181186147e4575b5050820160200191505090509050810190506101a0516102405260026102605250602061020061018461021c845afa614840573d600060003e3d6000fd5b60203d1061510357610200905051815250565b61485e610260613b4e565b61026051610240526148716102a0613752565b6102a0604061026060408360045afa50506040610360604061026060045afa5061489c6102e061396e565b6102e060406103a060408360045afa505060806040608061036060045afa506148c6610320613acb565b61032060406102a060408360045afa5050602061548c6000396000516350e7277d6103005260608061032052806103200160006102a0516104c0526102c0516104e05260026104a05260006104a0518084528060051b6000826008811161510357801561494d57905b8060051b6104c001518160051b60208901015260010181811861492f575b505082016020019150509050905081019050610240516103405260026103605250602061030061018461031c845afa61498b573d600060003e3d6000fd5b60203d10615103576103009050516102e052601954610300526102e051610200516102e05180820281158383830414171561510357905090506103005180156151035780820490509050808203828111615103579050905061032052602061548c600039600051637982c3406103605260a06102405161038052610220516103a052806103c052806103800160006102a051610560526102c051610580526002610540526000610540518084528060051b60008260088111615103578015614a6d57905b8060051b61056001518160051b602089010152600101818118614a4f575b505082016020019150509050905081019050610320516103e0526002610400525060206103606101c461037c845afa614aab573d600060003e3d6000fd5b60203d10615103576103609050516103405260035460011b60021c61036052604061038060406102a060045afa506102e05161032051808201828110615103579050905060021c6103c0526080366103e03760006002905b806104605260006103e05261046051600181116151035760051b6102a0015161040052610220516104605118614b9857610400516103205180820281158383830414171561510357905090506102e051801561510357808204905090506103405180820382811161510357905090506103e0526104005161034051808201828110615103579050905060011c61042052614be4565b61040051610400516103205180820281158383830414171561510357905090506102e0518015615103578082049050905080820382811161510357905090506103e05261040051610420525b610420516040526103c05160605261036051608052614c04610480613c59565b6104805161044052610400516402540be400610440516103e051808202811583838304141715615103579050905004808203828111615103579050905061046051600181116151035760051b6103800152600101818118614b0357505061022051600181116151035760051b6103800151602061548c600039600051637982c3406104805260a0610240516104a052610220516104c052806104e052806104a001600061038051610680526103a0516106a0526002610660526000610660518084528060051b60008260088111615103578015614cfb57905b8060051b61068001518160051b602089010152600101818118614cdd575b50508201602001915050905090508101905061032051610500526002610520525060206104806101c461049c845afa614d39573d600060003e3d6000fd5b60203d106151035761048090505180820382811161510357905090506104605261022051600181116151035760051b6102a00151610340518082038281116151035790509050670de0b6b3a7640000810281670de0b6b3a764000082041861510357905061022051600181116151035760051b6102600151801561510357808204905090506104805261022051600181116151035760051b61026001516104605160018103818111615103579050670de0b6b3a7640000810281670de0b6b3a764000082041861510357905004610460526103405161022051600181116151035760051b6102a001526104605181526104805161046051808203828111615103579050905060208201526040810160408160406102a060045afa50506102405160808201526103205160a082015250565b6019546060518082038281116151035790509050601955601760405160205260005260406000208054606051808203828111615103579050905081555060006040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60605160805260206080a3565b60206154ac60003960005163cab4d3db610160526020610160600461017c845afa614f0a573d600060003e3d6000fd5b60203d1061510357610160518060a01c615103576101a0526101a09050516101405261014051614f3957614fec565b60095460208160051b01600081601f0160051c60098111615103578015614f7557905b80600901548160051b6101600152600101818118614f5c575b5050505060006002905b806102805261028051610160518110156151035760051b610180015115614fd0576102805160405261028051610160518110156151035760051b610180015160605261014051608052614fd0613569565b600101818118614f7f5750506000600a556000600b5560026009555b565b602061576c6000396000514614615078577fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472606052602061574c6080397f1c54f243822e0e9a0a377610b81577e771b3efe79964e76636b0d5d10247950d60a0524660c0523060e052602061578c6101003960c06040526040805160208201209050815250615081565b60206157ac8239505b565b601760405160205260005260406000208054608051808203828111615103579050905081555060176060516020526000526040600020805460805180820182811061510357905090508155506060516040517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60805160a052602060a0a3565b600080fd062951300a008151a0090073526b0604dc521e0b002b52db07054452950a000d517606020251df09bb7b8b8027f705140522880131057e3db03003b985f446c1d02a7105015c28382ea0457ecebe0002f62529357750006a05551a65882df90554fd4d5002180576a2f0f02a8a0576a9cd3e2be845a6417ed604558544ee1986045fa571511a5e007505dd62ed3e02af45d52d5b860091250e71d1b925936514f059792abe0570a08231028725fee3f7f900fe054903b0d12a9a253da575a1008305fd0684b12b530595d89b4101c4051ddc3b01016f05313ce567020d0507211ef726fb65cc2b27d727af455e0d443f2647653eb1719f19fd85c661065700bb258edfdd5f00f20590d208371df625d505accf2193e5687276531f7c25db1bb01b1a17a565bbea6b2f6045bfa0b133031e05ddca3f4300e605ed8e84f3297165095ea7b321274506fdde03017b05e310327313a465a9059cbb1ff445907a016b1fc3051a4d01d211a8653931ab521dd125ec0238621e0c25afb4301203c3a55409491a010d0567df02ca24df650b4c7e4d09ac6523b872dd20256530c540851dc7051be913a50157053644e51524cd05b4b577ad01190552d2cfdd13ae85081579a511b28518160ddd27e105ddc1f59d0336a53c157e642c95450c3e4b5409b6855b36389c19ed653df02124032c852081066c012505e2e7d264013d259c4258c40163058419530c8918281846182a183f183f184d182a184618311904c0a16576797065728300030a0027
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.