Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
SigmaIndexPoolV1
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; /* ========== Internal Inheritance ========== */ import "./BToken.sol"; import "./BMath.sol"; /* ========== Internal Interfaces ========== */ import "../interfaces/IIndexPool.sol"; import "../interfaces/ICompLikeToken.sol"; /************************************************************************************************ Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol This source code has been modified from the original, which was copied from the github repository at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f. Subject to the GPL-3.0 license *************************************************************************************************/ contract SigmaIndexPoolV1 is BToken, BMath, IIndexPool { /* ========== EVENTS ========== */ /** @dev Emitted when tokens are swapped. */ event LOG_SWAP( address indexed caller, address indexed tokenIn, address indexed tokenOut, uint256 tokenAmountIn, uint256 tokenAmountOut ); /** @dev Emitted when underlying tokens are deposited for pool tokens. */ event LOG_JOIN( address indexed caller, address indexed tokenIn, uint256 tokenAmountIn ); /** @dev Emitted when pool tokens are burned for underlying. */ event LOG_EXIT( address indexed caller, address indexed tokenOut, uint256 tokenAmountOut ); /** @dev Emitted when a token's weight updates. */ event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm); /** @dev Emitted when a token's desired weight is set. */ event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm); /** @dev Emitted when a token is unbound from the pool. */ event LOG_TOKEN_REMOVED(address token); /** @dev Emitted when a token is unbound from the pool. */ event LOG_TOKEN_ADDED( address indexed token, uint256 desiredDenorm, uint256 minimumBalance ); /** @dev Emitted when a token's minimum balance is updated. */ event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance); /** @dev Emitted when a token reaches its minimum balance. */ event LOG_TOKEN_READY(address indexed token); /** @dev Emitted when public trades are disabled. */ event LOG_PUBLIC_SWAP_TOGGLED(bool enabled); /** @dev Emitted when the swap fee is updated. */ event LOG_SWAP_FEE_UPDATED(uint256 swapFee); /* ========== Modifiers ========== */ modifier _lock_ { require(!_mutex, "ERR_REENTRY"); _mutex = true; _; _mutex = false; } modifier _viewlock_() { require(!_mutex, "ERR_REENTRY"); _; } modifier _control_ { require(msg.sender == _controller, "ERR_NOT_CONTROLLER"); _; } modifier _public_ { require(_publicSwap, "ERR_NOT_PUBLIC"); _; } /* ========== Storage ========== */ bool internal _mutex; // Account with CONTROL role. Able to modify the swap fee, // adjust token weights, bind and unbind tokens and lock // public swaps & joins. address internal _controller; // Contract that handles unbound tokens. TokenUnbindHandler internal _unbindHandler; // True if PUBLIC can call SWAP & JOIN functions bool internal _publicSwap; // `setSwapFee` requires CONTROL uint256 internal _swapFee; // Array of underlying tokens in the pool. address[] internal _tokens; // Internal records of the pool's underlying tokens mapping(address => Record) internal _records; // Total denormalized weight of the pool. uint256 internal _totalWeight; // Minimum balances for tokens which have been added without the // requisite initial balance. mapping(address => uint256) internal _minimumBalances; // Recipient for exit fees address internal _exitFeeRecipient; /* ========== Controls ========== */ /** * @dev Sets the controller address and the token name & symbol. * * Note: This saves on storage costs for multi-step pool deployment. * * @param controller Controller of the pool * @param name Name of the pool token * @param symbol Symbol of the pool token */ function configure( address controller, string calldata name, string calldata symbol ) external override { require(_controller == address(0), "ERR_CONFIGURED"); require(controller != address(0), "ERR_NULL_ADDRESS"); _controller = controller; // default fee is 2.5% _swapFee = BONE / 40; _initializeToken(name, symbol); } /** * @dev Sets up the initial assets for the pool. * * Note: `tokenProvider` must have approved the pool to transfer the * corresponding `balances` of `tokens`. * * @param tokens Underlying tokens to initialize the pool with * @param balances Initial balances to transfer * @param denorms Initial denormalized weights for the tokens * @param tokenProvider Address to transfer the balances from * @param unbindHandler Address that receives tokens removed from the pool * @param exitFeeRecipient Address that receives exit fees */ function initialize( address[] calldata tokens, uint256[] calldata balances, uint96[] calldata denorms, address tokenProvider, address unbindHandler, address exitFeeRecipient ) external override _control_ { require(_tokens.length == 0, "ERR_INITIALIZED"); uint256 len = tokens.length; require(len >= MIN_BOUND_TOKENS, "ERR_MIN_TOKENS"); require(len <= MAX_BOUND_TOKENS, "ERR_MAX_TOKENS"); require(balances.length == len && denorms.length == len, "ERR_ARR_LEN"); uint256 totalWeight = 0; for (uint256 i = 0; i < len; i++) { address token = tokens[i]; uint96 denorm = denorms[i]; uint256 balance = balances[i]; require(denorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT"); require(denorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT"); require(balance >= MIN_BALANCE, "ERR_MIN_BALANCE"); _records[token] = Record({ bound: true, ready: true, lastDenormUpdate: uint40(now), denorm: denorm, desiredDenorm: denorm, index: uint8(i), balance: balance }); _tokens.push(token); totalWeight = badd(totalWeight, denorm); _pullUnderlying(token, tokenProvider, balance); } require(totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); _totalWeight = totalWeight; _publicSwap = true; emit LOG_PUBLIC_SWAP_TOGGLED(true); _mintPoolShare(INIT_POOL_SUPPLY); _pushPoolShare(tokenProvider, INIT_POOL_SUPPLY); _unbindHandler = TokenUnbindHandler(unbindHandler); _exitFeeRecipient = exitFeeRecipient; } /** * @dev Set the swap fee. * Note: Swap fee must be between 0.0001% and 10% */ function setSwapFee(uint256 swapFee) external override _control_ { require(swapFee >= MIN_FEE && swapFee <= MAX_FEE, "ERR_INVALID_FEE"); _swapFee = swapFee; emit LOG_SWAP_FEE_UPDATED(swapFee); } /** * @dev Delegate a comp-like governance token to an address * specified by the controller. */ function delegateCompLikeToken(address token, address delegatee) external override _control_ { ICompLikeToken(token).delegate(delegatee); } /** * @dev Set the exit fee recipient address. Can only be called * by the current exit fee recipient. */ function setExitFeeRecipient(address exitFeeRecipient) external override { require(msg.sender == _exitFeeRecipient, "ERR_NOT_FEE_RECIPIENT"); _exitFeeRecipient = exitFeeRecipient; } /** * @dev Toggle public trading for the index pool. * This will enable or disable swaps and single-token joins and exits. */ function setPublicSwap(bool enabled) external override _control_ { _publicSwap = enabled; emit LOG_PUBLIC_SWAP_TOGGLED(enabled); } /* ========== Token Management Actions ========== */ /** * @dev Sets the desired weights for the pool tokens, which * will be adjusted over time as they are swapped. * * Note: This does not check for duplicate tokens or that the total * of the desired weights is equal to the target total weight (25). * Those assumptions should be met in the controller. Further, the * provided tokens should only include the tokens which are not set * for removal. */ function reweighTokens( address[] calldata tokens, uint96[] calldata desiredDenorms ) external override _lock_ _control_ { require(desiredDenorms.length == tokens.length, "ERR_ARR_LEN"); for (uint256 i = 0; i < tokens.length; i++) _setDesiredDenorm(tokens[i], desiredDenorms[i]); } /** * @dev Update the underlying assets held by the pool and their associated * weights. Tokens which are not currently bound will be gradually added * as they are swapped in to reach the provided minimum balances, which must * be an amount of tokens worth the minimum weight of the total pool value. * If a currently bound token is not received in this call, the token's * desired weight will be set to 0. */ function reindexTokens( address[] calldata tokens, uint96[] calldata desiredDenorms, uint256[] calldata minimumBalances ) external override _lock_ _control_ { require( desiredDenorms.length == tokens.length && minimumBalances.length == tokens.length, "ERR_ARR_LEN" ); // This size may not be the same as the input size, as it is possible // to temporarily exceed the index size while tokens are being phased in // or out. uint256 tLen = _tokens.length; bool[] memory receivedIndices = new bool[](tLen); // We need to read token records in two separate loops, so // write them to memory to avoid duplicate storage reads. Record[] memory records = new Record[](tokens.length); // Read all the records from storage and mark which of the existing tokens // were represented in the reindex call. for (uint256 i = 0; i < tokens.length; i++) { records[i] = _records[tokens[i]]; if (records[i].bound) receivedIndices[records[i].index] = true; } // If any bound tokens were not sent in this call, set their desired weights to 0. for (uint256 i = 0; i < tLen; i++) { if (!receivedIndices[i]) { _setDesiredDenorm(_tokens[i], 0); } } for (uint256 i = 0; i < tokens.length; i++) { address token = tokens[i]; // If an input weight is less than the minimum weight, use that instead. uint96 denorm = desiredDenorms[i]; if (denorm < MIN_WEIGHT) denorm = uint96(MIN_WEIGHT); if (!records[i].bound) { // If the token is not bound, bind it. _bind(token, minimumBalances[i], denorm); } else { _setDesiredDenorm(token, denorm); } } } /** * @dev Updates the minimum balance for an uninitialized token. * This becomes useful if a token's external price significantly * rises after being bound, since the pool can not send a token * out until it reaches the minimum balance. */ function setMinimumBalance( address token, uint256 minimumBalance ) external override _control_ { Record storage record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); require(!record.ready, "ERR_READY"); _minimumBalances[token] = minimumBalance; emit LOG_MINIMUM_BALANCE_UPDATED(token, minimumBalance); } /* ========== Liquidity Provider Actions ========== */ /** * @dev Mint new pool tokens by providing the proportional amount of each * underlying token's balance relative to the proportion of pool tokens minted. * * For any underlying tokens which are not initialized, the caller must provide * the proportional share of the minimum balance for the token rather than the * actual balance. * * @param poolAmountOut Amount of pool tokens to mint * @param maxAmountsIn Maximum amount of each token to pay in the same * order as the pool's _tokens list. */ function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external override _lock_ _public_ { uint256 poolTotal = totalSupply(); uint256 ratio = bdiv(poolAmountOut, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); require(maxAmountsIn.length == _tokens.length, "ERR_ARR_LEN"); for (uint256 i = 0; i < maxAmountsIn.length; i++) { address t = _tokens[i]; (Record memory record, uint256 realBalance) = _getInputToken(t); uint256 tokenAmountIn = bmul(ratio, record.balance); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN"); _updateInputToken(t, record, badd(realBalance, tokenAmountIn)); emit LOG_JOIN(msg.sender, t, tokenAmountIn); _pullUnderlying(t, msg.sender, tokenAmountIn); } _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); } /** * @dev Pay `tokenAmountIn` of `tokenIn` to mint at least `minPoolAmountOut` * pool tokens. * * The pool implicitly swaps `(1- weightTokenIn) * tokenAmountIn` to the other * underlying tokens. Thus a swap fee is charged against the input tokens. * * @param tokenIn Token to send the pool * @param tokenAmountIn Exact amount of `tokenIn` to pay * @param minPoolAmountOut Minimum amount of pool tokens to mint * @return poolAmountOut - Amount of pool tokens minted */ function joinswapExternAmountIn( address tokenIn, uint256 tokenAmountIn, uint256 minPoolAmountOut ) external override _lock_ _public_ returns (uint256/* poolAmountOut */) { (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn); require(tokenAmountIn != 0, "ERR_ZERO_IN"); require( tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO" ); uint256 poolAmountOut = calcPoolOutGivenSingleIn( inRecord.balance, inRecord.denorm, _totalSupply, _totalWeight, tokenAmountIn, _swapFee ); require(poolAmountOut >= minPoolAmountOut, "ERR_LIMIT_OUT"); _updateInputToken(tokenIn, inRecord, badd(realInBalance, tokenAmountIn)); emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return poolAmountOut; } /** * @dev Pay up to `maxAmountIn` of `tokenIn` to mint exactly `poolAmountOut`. * * The pool implicitly swaps `(1- weightTokenIn) * tokenAmountIn` to the other * underlying tokens. Thus a swap fee is charged against the input tokens. * * @param tokenIn Token to send the pool * @param poolAmountOut Exact amount of pool tokens to mint * @param maxAmountIn Maximum amount of `tokenIn` to pay * @return tokenAmountIn - Amount of `tokenIn` paid */ function joinswapPoolAmountOut( address tokenIn, uint256 poolAmountOut, uint256 maxAmountIn ) external override _lock_ _public_ returns (uint256/* tokenAmountIn */) { (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn); uint256 tokenAmountIn = calcSingleInGivenPoolOut( inRecord.balance, inRecord.denorm, _totalSupply, _totalWeight, poolAmountOut, _swapFee ); require(tokenAmountIn != 0, "ERR_MATH_APPROX"); require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN"); require( tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO" ); _updateInputToken(tokenIn, inRecord, badd(realInBalance, tokenAmountIn)); emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn); _mintPoolShare(poolAmountOut); _pushPoolShare(msg.sender, poolAmountOut); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); return tokenAmountIn; } /** * @dev Burns `poolAmountIn` pool tokens in exchange for the amounts of each * underlying token's balance proportional to the ratio of tokens burned to * total pool supply. The amount of each token transferred to the caller must * be greater than or equal to the associated minimum output amount from the * `minAmountsOut` array. * * @param poolAmountIn Exact amount of pool tokens to burn * @param minAmountsOut Minimum amount of each token to receive, in the same * order as the pool's _tokens list. */ function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external override _lock_ { require(minAmountsOut.length == _tokens.length, "ERR_ARR_LEN"); uint256 poolTotal = totalSupply(); uint256 exitFee = bmul(poolAmountIn, EXIT_FEE); uint256 pAiAfterExitFee = bsub(poolAmountIn, exitFee); uint256 ratio = bdiv(pAiAfterExitFee, poolTotal); require(ratio != 0, "ERR_MATH_APPROX"); _pullPoolShare(msg.sender, poolAmountIn); _pushPoolShare(_exitFeeRecipient, exitFee); _burnPoolShare(pAiAfterExitFee); for (uint256 i = 0; i < minAmountsOut.length; i++) { address t = _tokens[i]; Record memory record = _records[t]; if (record.ready) { uint256 tokenAmountOut = bmul(ratio, record.balance); require(tokenAmountOut != 0, "ERR_MATH_APPROX"); require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT"); _records[t].balance = bsub(record.balance, tokenAmountOut); emit LOG_EXIT(msg.sender, t, tokenAmountOut); _pushUnderlying(t, msg.sender, tokenAmountOut); } else { // If the token is not initialized, it can not exit the pool. require(minAmountsOut[i] == 0, "ERR_OUT_NOT_READY"); } } } /** * @dev Burns `poolAmountIn` pool tokens in exchange for at least `minAmountOut` * of `tokenOut`. Returns the number of tokens sent to the caller. * * The pool implicitly burns the tokens for all underlying tokens and swaps them * to the desired output token. A swap fee is charged against the output tokens. * * @param tokenOut Token to receive * @param poolAmountIn Exact amount of pool tokens to burn * @param minAmountOut Minimum amount of `tokenOut` to receive * @return tokenAmountOut - Amount of `tokenOut` received */ function exitswapPoolAmountIn( address tokenOut, uint256 poolAmountIn, uint256 minAmountOut ) external override _lock_ returns (uint256/* tokenAmountOut */) { Record memory outRecord = _getOutputToken(tokenOut); uint256 tokenAmountOut = calcSingleOutGivenPoolIn( outRecord.balance, outRecord.denorm, _totalSupply, _totalWeight, poolAmountIn, _swapFee ); require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT"); require( tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO" ); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); _records[tokenOut].balance = bsub(outRecord.balance, tokenAmountOut); _decreaseDenorm(outRecord, tokenOut); uint256 exitFee = bmul(poolAmountIn, EXIT_FEE); emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(bsub(poolAmountIn, exitFee)); _pushPoolShare(_exitFeeRecipient, exitFee); return tokenAmountOut; } /** * @dev Burn up to `maxPoolAmountIn` for exactly `tokenAmountOut` of `tokenOut`. * Returns the number of pool tokens burned. * * The pool implicitly burns the tokens for all underlying tokens and swaps them * to the desired output token. A swap fee is charged against the output tokens. * * @param tokenOut Token to receive * @param tokenAmountOut Exact amount of `tokenOut` to receive * @param maxPoolAmountIn Maximum amount of pool tokens to burn * @return poolAmountIn - Amount of pool tokens burned */ function exitswapExternAmountOut( address tokenOut, uint256 tokenAmountOut, uint256 maxPoolAmountIn ) external override _lock_ returns (uint256/* poolAmountIn */) { Record memory outRecord = _getOutputToken(tokenOut); require( tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO" ); uint256 poolAmountIn = calcPoolInGivenSingleOut( outRecord.balance, outRecord.denorm, _totalSupply, _totalWeight, tokenAmountOut, _swapFee ); require(poolAmountIn != 0, "ERR_MATH_APPROX"); require(poolAmountIn <= maxPoolAmountIn, "ERR_LIMIT_IN"); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); _records[tokenOut].balance = bsub(outRecord.balance, tokenAmountOut); _decreaseDenorm(outRecord, tokenOut); uint256 exitFee = bmul(poolAmountIn, EXIT_FEE); emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut); _pullPoolShare(msg.sender, poolAmountIn); _burnPoolShare(bsub(poolAmountIn, exitFee)); _pushPoolShare(_exitFeeRecipient, exitFee); return poolAmountIn; } /* ========== Other ========== */ /** * @dev Absorb any tokens that have been sent to the pool. * If the token is not bound, it will be sent to the unbound * token handler. */ function gulp(address token) external override _lock_ { Record storage record = _records[token]; uint256 balance = IERC20(token).balanceOf(address(this)); if (record.bound) { if (!record.ready) { uint256 minimumBalance = _minimumBalances[token]; if (balance >= minimumBalance) { _minimumBalances[token] = 0; record.ready = true; emit LOG_TOKEN_READY(token); uint256 additionalBalance = bsub(balance, minimumBalance); uint256 balRatio = bdiv(additionalBalance, minimumBalance); uint96 newDenorm = uint96(badd(MIN_WEIGHT, bmul(MIN_WEIGHT, balRatio))); record.denorm = newDenorm; record.lastDenormUpdate = uint40(now); _totalWeight = badd(_totalWeight, newDenorm); emit LOG_DENORM_UPDATED(token, record.denorm); } } _records[token].balance = balance; } else { _pushUnderlying(token, address(_unbindHandler), balance); _unbindHandler.handleUnbindToken(token, balance); } } /* ========== Token Swaps ========== */ /** * @dev Execute a token swap with a specified amount of input * tokens and a minimum amount of output tokens. * * Note: Will revert if `tokenOut` is uninitialized. * * @param tokenIn Token to swap in * @param tokenAmountIn Exact amount of `tokenIn` to swap in * @param tokenOut Token to swap out * @param minAmountOut Minimum amount of `tokenOut` to receive * @param maxPrice Maximum ratio of input to output tokens * @return (tokenAmountOut, spotPriceAfter) */ function swapExactAmountIn( address tokenIn, uint256 tokenAmountIn, address tokenOut, uint256 minAmountOut, uint256 maxPrice ) external override _lock_ _public_ returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */) { (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn); Record memory outRecord = _getOutputToken(tokenOut); require( tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO), "ERR_MAX_IN_RATIO" ); uint256 spotPriceBefore = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE"); uint256 tokenAmountOut = calcOutGivenIn( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, tokenAmountIn, _swapFee ); require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT"); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); realInBalance = badd(realInBalance, tokenAmountIn); _updateInputToken(tokenIn, inRecord, realInBalance); if (inRecord.ready) { inRecord.balance = realInBalance; } // Update the in-memory record for the spotPriceAfter calculation, // then update the storage record with the local balance. outRecord.balance = bsub(outRecord.balance, tokenAmountOut); _records[tokenOut].balance = outRecord.balance; // If needed, update the output token's weight. _decreaseDenorm(outRecord, tokenOut); uint256 spotPriceAfter = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX_2"); require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE"); require( spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut), "ERR_MATH_APPROX" ); emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut); return (tokenAmountOut, spotPriceAfter); } /** * @dev Trades at most `maxAmountIn` of `tokenIn` for exactly `tokenAmountOut` * of `tokenOut`. * * Returns the actual input amount and the new spot price after the swap, * which can not exceed `maxPrice`. * * @param tokenIn Token to swap in * @param maxAmountIn Maximum amount of `tokenIn` to pay * @param tokenOut Token to swap out * @param tokenAmountOut Exact amount of `tokenOut` to receive * @param maxPrice Maximum ratio of input to output tokens * @return (tokenAmountIn, spotPriceAfter) */ function swapExactAmountOut( address tokenIn, uint256 maxAmountIn, address tokenOut, uint256 tokenAmountOut, uint256 maxPrice ) external override _lock_ _public_ returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */) { (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn); Record memory outRecord = _getOutputToken(tokenOut); require( tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO), "ERR_MAX_OUT_RATIO" ); uint256 spotPriceBefore = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE"); uint256 tokenAmountIn = calcInGivenOut( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, tokenAmountOut, _swapFee ); require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN"); _pullUnderlying(tokenIn, msg.sender, tokenAmountIn); _pushUnderlying(tokenOut, msg.sender, tokenAmountOut); // Update the balance and (if necessary) weight of the input token. realInBalance = badd(realInBalance, tokenAmountIn); _updateInputToken(tokenIn, inRecord, realInBalance); if (inRecord.ready) { inRecord.balance = realInBalance; } // Update the in-memory record for the spotPriceAfter calculation, // then update the storage record with the local balance. outRecord.balance = bsub(outRecord.balance, tokenAmountOut); _records[tokenOut].balance = outRecord.balance; // If needed, update the output token's weight. _decreaseDenorm(outRecord, tokenOut); uint256 spotPriceAfter = calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX"); require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE"); require( spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut), "ERR_MATH_APPROX" ); emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut); return (tokenAmountIn, spotPriceAfter); } /* ========== Config Queries ========== */ /** * @dev Check if swapping tokens and joining the pool is allowed. */ function isPublicSwap() external view override returns (bool) { return _publicSwap; } function getSwapFee() external view override _viewlock_ returns (uint256/* swapFee */) { return _swapFee; } /** * @dev Returns the controller address. */ function getController() external view override returns (address) { return _controller; } /** * @dev Returns the exit fee recipient address. */ function getExitFeeRecipient() external view override returns (address) { return _exitFeeRecipient; } /* ========== Token Queries ========== */ /** * @dev Check if a token is bound to the pool. */ function isBound(address t) external view override returns (bool) { return _records[t].bound; } /** * @dev Get the number of tokens bound to the pool. */ function getNumTokens() external view override returns (uint256) { return _tokens.length; } /** * @dev Get all bound tokens. */ function getCurrentTokens() external view override _viewlock_ returns (address[] memory tokens) { tokens = _tokens; } /** * @dev Returns the list of tokens which have a desired weight above 0. * Tokens with a desired weight of 0 are set to be phased out of the pool. */ function getCurrentDesiredTokens() external view override _viewlock_ returns (address[] memory tokens) { address[] memory tempTokens = _tokens; tokens = new address[](tempTokens.length); uint256 usedIndex = 0; for (uint256 i = 0; i < tokens.length; i++) { address token = tempTokens[i]; if (_records[token].desiredDenorm > 0) { tokens[usedIndex++] = token; } } assembly { mstore(tokens, usedIndex) } } /** * @dev Returns the denormalized weight of a bound token. */ function getDenormalizedWeight(address token) external view override _viewlock_ returns (uint256/* denorm */) { require(_records[token].bound, "ERR_NOT_BOUND"); return _records[token].denorm; } /** * @dev Returns the record for a token bound to the pool. */ function getTokenRecord(address token) external view override _viewlock_ returns (Record memory record) { record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); } /** * @dev Finds the first token which is both initialized and has a * desired weight above 0, then returns the address of that token * and the extrapolated value of the pool in terms of that token. * * The value is extrapolated by multiplying the token's * balance by the reciprocal of its normalized weight. * @return (token, extrapolatedValue) */ function extrapolatePoolValueFromToken() external view override _viewlock_ returns (address/* token */, uint256/* extrapolatedValue */) { address token; uint256 extrapolatedValue; uint256 len = _tokens.length; for (uint256 i = 0; i < len; i++) { token = _tokens[i]; Record storage record = _records[token]; if (record.ready && record.desiredDenorm > 0) { extrapolatedValue = bmul( record.balance, bdiv(_totalWeight, record.denorm) ); break; } } require(extrapolatedValue > 0, "ERR_NONE_READY"); return (token, extrapolatedValue); } /** * @dev Get the total denormalized weight of the pool. */ function getTotalDenormalizedWeight() external view override _viewlock_ returns (uint256) { return _totalWeight; } /** * @dev Returns the stored balance of a bound token. */ function getBalance(address token) external view override _viewlock_ returns (uint256) { Record storage record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); return record.balance; } /** * @dev Get the minimum balance of an uninitialized token. * Note: Throws if the token is initialized. */ function getMinimumBalance(address token) external view override _viewlock_ returns (uint256) { Record memory record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); require(!record.ready, "ERR_READY"); return _minimumBalances[token]; } /** * @dev Returns the balance of a token which is used in price * calculations. If the token is initialized, this is the * stored balance; if not, this is the minimum balance. */ function getUsedBalance(address token) external view override _viewlock_ returns (uint256) { Record memory record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); if (!record.ready) { return _minimumBalances[token]; } return record.balance; } /* ========== Price Queries ========== */ /** * @dev Returns the spot price for `tokenOut` in terms of `tokenIn`. */ function getSpotPrice(address tokenIn, address tokenOut) external view override _viewlock_ returns (uint256) { (Record memory inRecord,) = _getInputToken(tokenIn); Record memory outRecord = _getOutputToken(tokenOut); return calcSpotPrice( inRecord.balance, inRecord.denorm, outRecord.balance, outRecord.denorm, _swapFee ); } /* ========== Pool Share Internal Functions ========== */ function _pullPoolShare(address from, uint256 amount) internal { _pull(from, amount); } function _pushPoolShare(address to, uint256 amount) internal { _push(to, amount); } function _mintPoolShare(uint256 amount) internal { _mint(amount); } function _burnPoolShare(uint256 amount) internal { _burn(amount); } /* ========== Underlying Token Internal Functions ========== */ // 'Underlying' token-manipulation functions make external calls but are NOT locked // You must `_lock_` or otherwise ensure reentry-safety function _pullUnderlying( address erc20, address from, uint256 amount ) internal { (bool success, bytes memory data) = erc20.call( abi.encodeWithSelector( IERC20.transferFrom.selector, from, address(this), amount ) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "ERR_ERC20_FALSE" ); } function _pushUnderlying( address erc20, address to, uint256 amount ) internal { (bool success, bytes memory data) = erc20.call( abi.encodeWithSelector( IERC20.transfer.selector, to, amount ) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "ERR_ERC20_FALSE" ); } /* ========== Token Management Internal Functions ========== */ /** * @dev Bind a token by address without actually depositing a balance. * The token will be unable to be swapped out until it reaches the minimum balance. * Note: Token must not already be bound. * Note: `minimumBalance` should represent an amount of the token which is worth * the portion of the current pool value represented by the minimum weight. * @param token Address of the token to bind * @param minimumBalance minimum balance to reach before the token can be swapped out * @param desiredDenorm Desired weight for the token. */ function _bind( address token, uint256 minimumBalance, uint96 desiredDenorm ) internal { require(!_records[token].bound, "ERR_IS_BOUND"); require(desiredDenorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT"); require(desiredDenorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT"); require(minimumBalance >= MIN_BALANCE, "ERR_MIN_BALANCE"); _records[token] = Record({ bound: true, ready: false, lastDenormUpdate: 0, denorm: 0, desiredDenorm: desiredDenorm, index: uint8(_tokens.length), balance: 0 }); _tokens.push(token); _minimumBalances[token] = minimumBalance; emit LOG_TOKEN_ADDED(token, desiredDenorm, minimumBalance); } /** * @dev Remove a token from the pool. * Replaces the address in the tokens array with the last address, * then removes it from the array. * Note: This should only be called after the total weight has been adjusted. * Note: Must be called in a function with: * - _lock_ modifier to prevent reentrance * - requirement that the token is bound */ function _unbind(address token) internal { Record memory record = _records[token]; uint256 tokenBalance = record.balance; // Swap the token-to-unbind with the last token, // then delete the last token uint256 index = record.index; uint256 last = _tokens.length - 1; // Only swap the token with the last token if it is not // already at the end of the array. if (index != last) { _tokens[index] = _tokens[last]; _records[_tokens[index]].index = uint8(index); } _tokens.pop(); _records[token] = Record({ bound: false, ready: false, lastDenormUpdate: 0, denorm: 0, desiredDenorm: 0, index: 0, balance: 0 }); // transfer any remaining tokens out _pushUnderlying(token, address(_unbindHandler), tokenBalance); _unbindHandler.handleUnbindToken(token, tokenBalance); emit LOG_TOKEN_REMOVED(token); } function _setDesiredDenorm(address token, uint96 desiredDenorm) internal { Record storage record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); // If the desired weight is 0, this will trigger a gradual unbinding of the token. // Therefore the weight only needs to be above the minimum weight if it isn't 0. require( desiredDenorm >= MIN_WEIGHT || desiredDenorm == 0, "ERR_MIN_WEIGHT" ); require(desiredDenorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT"); record.desiredDenorm = desiredDenorm; emit LOG_DESIRED_DENORM_SET(token, desiredDenorm); } function _increaseDenorm(Record memory record, address token) internal { // If the weight does not need to increase or the token is not // initialized, don't do anything. if ( record.denorm >= record.desiredDenorm || !record.ready || now - record.lastDenormUpdate < WEIGHT_UPDATE_DELAY ) return; uint96 oldWeight = record.denorm; uint96 denorm = record.desiredDenorm; uint256 maxDiff = bmul(oldWeight, WEIGHT_CHANGE_PCT); uint256 diff = bsub(denorm, oldWeight); if (diff > maxDiff) { denorm = uint96(badd(oldWeight, maxDiff)); diff = maxDiff; } _totalWeight = badd(_totalWeight, diff); require(_totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT"); // Update the in-memory denorm value for spot-price computations. record.denorm = denorm; // Update the storage record _records[token].denorm = denorm; _records[token].lastDenormUpdate = uint40(now); emit LOG_DENORM_UPDATED(token, denorm); } function _decreaseDenorm(Record memory record, address token) internal { // If the weight does not need to decrease, don't do anything. if ( record.denorm <= record.desiredDenorm || !record.ready || now - record.lastDenormUpdate < WEIGHT_UPDATE_DELAY ) return; uint96 oldWeight = record.denorm; uint96 denorm = record.desiredDenorm; uint256 maxDiff = bmul(oldWeight, WEIGHT_CHANGE_PCT); uint256 diff = bsub(oldWeight, denorm); if (diff > maxDiff) { denorm = uint96(bsub(oldWeight, maxDiff)); diff = maxDiff; } if (denorm <= MIN_WEIGHT) { denorm = 0; _totalWeight = bsub(_totalWeight, denorm); // Because this is removing the token from the pool, the // in-memory denorm value is irrelevant, as it is only used // to calculate the new spot price, but the spot price calc // will throw if it is passed 0 for the denorm. _unbind(token); } else { _totalWeight = bsub(_totalWeight, diff); // Update the in-memory denorm value for spot-price computations. record.denorm = denorm; // Update the stored denorm value _records[token].denorm = denorm; _records[token].lastDenormUpdate = uint40(now); emit LOG_DENORM_UPDATED(token, denorm); } } /** * @dev Handles weight changes and initialization of an * input token. * * If the token is not initialized and the new balance is * still below the minimum, this will not do anything. * * If the token is not initialized but the new balance will * bring the token above the minimum balance, this will * mark the token as initialized, remove the minimum * balance and set the weight to the minimum weight plus * 1%. * * * @param token Address of the input token * @param record Token record with minimums applied to the balance * and weight if the token was uninitialized. */ function _updateInputToken( address token, Record memory record, uint256 realBalance ) internal { if (!record.ready) { // Check if the minimum balance has been reached if (realBalance >= record.balance) { // Remove the minimum balance record _minimumBalances[token] = 0; // Mark the token as initialized _records[token].ready = true; record.ready = true; emit LOG_TOKEN_READY(token); // Set the initial denorm value to the minimum weight times one plus // the ratio of the increase in balance over the minimum to the minimum // balance. // weight = (1 + ((bal - min_bal) / min_bal)) * min_weight uint256 additionalBalance = bsub(realBalance, record.balance); uint256 balRatio = bdiv(additionalBalance, record.balance); record.denorm = uint96(badd(MIN_WEIGHT, bmul(MIN_WEIGHT, balRatio))); _records[token].denorm = record.denorm; _records[token].lastDenormUpdate = uint40(now); _totalWeight = badd(_totalWeight, record.denorm); emit LOG_DENORM_UPDATED(token, record.denorm); } else { uint256 realToMinRatio = bdiv( bsub(record.balance, realBalance), record.balance ); uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio); record.denorm = uint96(badd(MIN_WEIGHT, weightPremium)); } // If the token is still not ready, do not adjust the weight. } else { // If the token is already initialized, update the weight (if any adjustment // is needed). _increaseDenorm(record, token); } // Regardless of whether the token is initialized, store the actual new balance. _records[token].balance = realBalance; } /* ========== Token Query Internal Functions ========== */ /** * @dev Get the record for a token which is being swapped in. * The token must be bound to the pool. If the token is not * initialized (meaning it does not have the minimum balance) * this function will return the actual balance of the token * which the pool holds, but set the record's balance and weight * to the token's minimum balance and the pool's minimum weight. * This allows the token swap to be priced correctly even if the * pool does not own any of the tokens. */ function _getInputToken(address token) internal view returns (Record memory record, uint256 realBalance) { record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); realBalance = record.balance; // If the input token is not initialized, we use the minimum // initial weight and minimum initial balance instead of the // real values for price and output calculations. if (!record.ready) { record.balance = _minimumBalances[token]; uint256 realToMinRatio = bdiv( bsub(record.balance, realBalance), record.balance ); uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio); record.denorm = uint96(badd(MIN_WEIGHT, weightPremium)); } } function _getOutputToken(address token) internal view returns (Record memory record) { record = _records[token]; require(record.bound, "ERR_NOT_BOUND"); // Tokens which have not reached their minimum balance can not be // swapped out. require(record.ready, "ERR_OUT_NOT_READY"); } } interface TokenUnbindHandler { /** * @dev Receive `amount` of `token` from the pool. */ function handleUnbindToken(address token, uint256 amount) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; /************************************************************************************************ Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BConst.sol This source code has been modified from the original, which was copied from the github repository at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f. Subject to the GPL-3.0 license *************************************************************************************************/ contract BConst { uint256 public constant VERSION_NUMBER = 1; /* --- Weight Updates --- */ // Minimum time passed between each weight update for a token. uint256 internal constant WEIGHT_UPDATE_DELAY = 1 hours; // Maximum percent by which a weight can adjust at a time // relative to the current weight. // The number of iterations needed to move from weight A to weight B is the floor of: // (A > B): (ln(A) - ln(B)) / ln(1.01) // (B > A): (ln(A) - ln(B)) / ln(0.99) uint256 internal constant WEIGHT_CHANGE_PCT = BONE/100; uint256 internal constant BONE = 10**18; uint256 internal constant MIN_BOUND_TOKENS = 2; uint256 internal constant MAX_BOUND_TOKENS = 10; // Minimum swap fee. uint256 internal constant MIN_FEE = BONE / 10**6; // Maximum swap or exit fee. uint256 internal constant MAX_FEE = BONE / 10; // Actual exit fee. uint256 internal constant EXIT_FEE = 5e15; // Default total of all desired weights. Can differ by up to BONE. uint256 internal constant DEFAULT_TOTAL_WEIGHT = BONE * 25; // Minimum weight for any token (1/100). uint256 internal constant MIN_WEIGHT = BONE / 4; uint256 internal constant MAX_WEIGHT = BONE * 25; // Maximum total weight. uint256 internal constant MAX_TOTAL_WEIGHT = BONE * 26; // Minimum balance for a token (only applied at initialization) uint256 internal constant MIN_BALANCE = BONE / 10**12; // Initial pool tokens uint256 internal constant INIT_POOL_SUPPLY = BONE * 100; uint256 internal constant MIN_BPOW_BASE = 1 wei; uint256 internal constant MAX_BPOW_BASE = (2 * BONE) - 1 wei; uint256 internal constant BPOW_PRECISION = BONE / 10**10; // Maximum ratio of input tokens to balance for swaps. uint256 internal constant MAX_IN_RATIO = BONE / 2; // Maximum ratio of output tokens to balance for swaps. uint256 internal constant MAX_OUT_RATIO = (BONE / 3) + 1 wei; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; import "./BNum.sol"; /************************************************************************************************ Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BMath.sol This source code has been modified from the original, which was copied from the github repository at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f. Subject to the GPL-3.0 license *************************************************************************************************/ contract BMath is BConst, BNum { /********************************************************************************************** // calcSpotPrice // // sP = spotPrice // // bI = tokenBalanceIn ( bI / wI ) 1 // // bO = tokenBalanceOut sP = ----------- * ---------- // // wI = tokenWeightIn ( bO / wO ) ( 1 - sF ) // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcSpotPrice( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 swapFee ) internal pure returns (uint256 spotPrice) { uint256 numer = bdiv(tokenBalanceIn, tokenWeightIn); uint256 denom = bdiv(tokenBalanceOut, tokenWeightOut); uint256 ratio = bdiv(numer, denom); uint256 scale = bdiv(BONE, bsub(BONE, swapFee)); return (spotPrice = bmul(ratio, scale)); } /********************************************************************************************** // calcOutGivenIn // // aO = tokenAmountOut // // bO = tokenBalanceOut // // bI = tokenBalanceIn / / bI \ (wI / wO) \ // // aI = tokenAmountIn aO = bO * | 1 - | -------------------------- | ^ | // // wI = tokenWeightIn \ \ ( bI + ( aI * ( 1 - sF )) / / // // wO = tokenWeightOut // // sF = swapFee // **********************************************************************************************/ function calcOutGivenIn( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 tokenAmountIn, uint256 swapFee ) internal pure returns (uint256 tokenAmountOut) { uint256 weightRatio = bdiv(tokenWeightIn, tokenWeightOut); uint256 adjustedIn = bsub(BONE, swapFee); adjustedIn = bmul(tokenAmountIn, adjustedIn); uint256 y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn)); uint256 foo = bpow(y, weightRatio); uint256 bar = bsub(BONE, foo); tokenAmountOut = bmul(tokenBalanceOut, bar); return tokenAmountOut; } /********************************************************************************************** // calcInGivenOut // // aI = tokenAmountIn // // bO = tokenBalanceOut / / bO \ (wO / wI) \ // // bI = tokenBalanceIn bI * | | ------------ | ^ - 1 | // // aO = tokenAmountOut aI = \ \ ( bO - aO ) / / // // wI = tokenWeightIn -------------------------------------------- // // wO = tokenWeightOut ( 1 - sF ) // // sF = swapFee // **********************************************************************************************/ function calcInGivenOut( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 tokenAmountOut, uint256 swapFee ) internal pure returns (uint256 tokenAmountIn) { uint256 weightRatio = bdiv(tokenWeightOut, tokenWeightIn); uint256 diff = bsub(tokenBalanceOut, tokenAmountOut); uint256 y = bdiv(tokenBalanceOut, diff); uint256 foo = bpow(y, weightRatio); foo = bsub(foo, BONE); tokenAmountIn = bsub(BONE, swapFee); tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn); return tokenAmountIn; } /********************************************************************************************** // calcPoolOutGivenSingleIn // // pAo = poolAmountOut / \ // // tAi = tokenAmountIn /// / // wI \ \\ \ wI \ // // wI = tokenWeightIn //| tAi *| 1 - || 1 - -- | * sF || + tBi \ -- \ // // tW = totalWeight pAo=|| \ \ \\ tW / // | ^ tW | * pS - pS // // tBi = tokenBalanceIn \\ ------------------------------------- / / // // pS = poolSupply \\ tBi / / // // sF = swapFee \ / // **********************************************************************************************/ function calcPoolOutGivenSingleIn( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 poolSupply, uint256 totalWeight, uint256 tokenAmountIn, uint256 swapFee ) internal pure returns (uint256 poolAmountOut) { // Charge the trading fee for the proportion of tokenAi /// which is implicitly traded to the other pool tokens. // That proportion is (1- weightTokenIn) // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee); uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint256 zaz = bmul(bsub(BONE, normalizedWeight), swapFee); uint256 tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz)); uint256 newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee); uint256 tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn); // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply; uint256 poolRatio = bpow(tokenInRatio, normalizedWeight); uint256 newPoolSupply = bmul(poolRatio, poolSupply); poolAmountOut = bsub(newPoolSupply, poolSupply); return poolAmountOut; } /********************************************************************************************** // calcSingleInGivenPoolOut // // tAi = tokenAmountIn //(pS + pAo)\ / 1 \\ // // pS = poolSupply || --------- | ^ | --------- || * bI - bI // // pAo = poolAmountOut \\ pS / \(wI / tW)// // // bI = balanceIn tAi = -------------------------------------------- // // wI = weightIn / wI \ // // tW = totalWeight | 1 - ---- | * sF // // sF = swapFee \ tW / // **********************************************************************************************/ function calcSingleInGivenPoolOut( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountOut, uint256 swapFee ) internal pure returns (uint256 tokenAmountIn) { uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint256 newPoolSupply = badd(poolSupply, poolAmountOut); uint256 poolRatio = bdiv(newPoolSupply, poolSupply); //uint newBalTi = poolRatio^(1/weightTi) * balTi; uint256 boo = bdiv(BONE, normalizedWeight); uint256 tokenInRatio = bpow(poolRatio, boo); uint256 newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn); uint256 tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn); // Do reverse order of fees charged in joinswap_ExternAmountIn, this way // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ``` //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ; uint256 zar = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar)); return tokenAmountIn; } /********************************************************************************************** // calcSingleOutGivenPoolIn // // tAo = tokenAmountOut / / \\ // // bO = tokenBalanceOut / // pS - (pAi * (1 - eF)) \ / 1 \ \\ // // pAi = poolAmountIn | bO - || ----------------------- | ^ | --------- | * b0 || // // ps = poolSupply \ \\ pS / \(wO / tW)/ // // // wI = tokenWeightIn tAo = \ \ // // // tW = totalWeight / / wO \ \ // // sF = swapFee * | 1 - | 1 - ---- | * sF | // // eF = exitFee \ \ tW / / // **********************************************************************************************/ function calcSingleOutGivenPoolIn( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountIn, uint256 swapFee ) internal pure returns (uint256 tokenAmountOut) { uint256 normalizedWeight = bdiv(tokenWeightOut, totalWeight); // charge exit fee on the pool token side // pAiAfterExitFee = pAi*(1-exitFee) uint256 poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE)); uint256 newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee); uint256 poolRatio = bdiv(newPoolSupply, poolSupply); // newBalTo = poolRatio^(1/weightTo) * balTo; uint256 tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight)); uint256 newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut); uint256 tokenAmountOutBeforeSwapFee = bsub( tokenBalanceOut, newTokenBalanceOut ); // charge swap fee on the output token side //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee) uint256 zaz = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz)); return tokenAmountOut; } /********************************************************************************************** // calcPoolInGivenSingleOut // // pAi = poolAmountIn // / tAo \\ / wO \ \ // // bO = tokenBalanceOut // | bO - -------------------------- |\ | ---- | \ // // tAo = tokenAmountOut pS - || \ 1 - ((1 - (tO / tW)) * sF)/ | ^ \ tW / * pS | // // ps = poolSupply \\ -----------------------------------/ / // // wO = tokenWeightOut pAi = \\ bO / / // // tW = totalWeight ------------------------------------------------------------- // // sF = swapFee ( 1 - eF ) // // eF = exitFee // **********************************************************************************************/ function calcPoolInGivenSingleOut( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 tokenAmountOut, uint256 swapFee ) internal pure returns (uint256 poolAmountIn) { // charge swap fee on the output token side uint256 normalizedWeight = bdiv(tokenWeightOut, totalWeight); //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ; uint256 zoo = bsub(BONE, normalizedWeight); uint256 zar = bmul(zoo, swapFee); uint256 tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar)); uint256 newTokenBalanceOut = bsub( tokenBalanceOut, tokenAmountOutBeforeSwapFee ); uint256 tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut); //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply; uint256 poolRatio = bpow(tokenOutRatio, normalizedWeight); uint256 newPoolSupply = bmul(poolRatio, poolSupply); uint256 poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply); // charge exit fee on the pool token side // pAi = pAiAfterExitFee/(1-exitFee) poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE)); return poolAmountIn; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; import "./BConst.sol"; /************************************************************************************************ Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BNum.sol This source code has been modified from the original, which was copied from the github repository at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f. Subject to the GPL-3.0 license *************************************************************************************************/ contract BNum is BConst { function btoi(uint256 a) internal pure returns (uint256) { return a / BONE; } function bfloor(uint256 a) internal pure returns (uint256) { return btoi(a) * BONE; } function badd(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } function bsub(uint256 a, uint256 b) internal pure returns (uint256) { (uint256 c, bool flag) = bsubSign(a, b); require(!flag, "ERR_SUB_UNDERFLOW"); return c; } function bsubSign(uint256 a, uint256 b) internal pure returns (uint256, bool) { if (a >= b) { return (a - b, false); } else { return (b - a, true); } } function bmul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c0 = a * b; require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW"); uint256 c1 = c0 + (BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint256 c2 = c1 / BONE; return c2; } function bdiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "ERR_DIV_ZERO"); uint256 c0 = a * BONE; require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint256 c1 = c0 + (b / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint256 c2 = c1 / b; return c2; } // DSMath.wpow function bpowi(uint256 a, uint256 n) internal pure returns (uint256) { uint256 z = n % 2 != 0 ? a : BONE; for (n /= 2; n != 0; n /= 2) { a = bmul(a, a); if (n % 2 != 0) { z = bmul(z, a); } } return z; } // Compute b^(e.w) by splitting it into (b^e)*(b^0.w). // Use `bpowi` for `b^e` and `bpowK` for k iterations // of approximation of b^0.w function bpow(uint256 base, uint256 exp) internal pure returns (uint256) { require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW"); require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH"); uint256 whole = bfloor(exp); uint256 remain = bsub(exp, whole); uint256 wholePow = bpowi(base, btoi(whole)); if (remain == 0) { return wholePow; } uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION); return bmul(wholePow, partialResult); } function bpowApprox( uint256 base, uint256 exp, uint256 precision ) internal pure returns (uint256) { // term 0: uint256 a = exp; (uint256 x, bool xneg) = bsubSign(base, BONE); uint256 term = BONE; uint256 sum = term; bool negative = false; // term(k) = numer / denom // = (product(a - i - 1, i=1-->k) * x^k) / (k!) // each iteration, multiply previous term by (a-(k-1)) * x / k // continue until term is less than precision for (uint256 i = 1; term >= precision; i++) { uint256 bigK = i * BONE; (uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE)); term = bmul(term, bmul(c, x)); term = bdiv(term, bigK); if (term == 0) break; if (xneg) negative = !negative; if (cneg) negative = !negative; if (negative) { sum = bsub(sum, term); } else { sum = badd(sum, term); } } return sum; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; import "./BNum.sol"; /************************************************************************************************ Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BToken.sol This source code has been modified from the original, which was copied from the github repository at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f. Subject to the GPL-3.0 license *************************************************************************************************/ // Highly opinionated token implementation interface IERC20 { event Approval(address indexed src, address indexed dst, uint256 amt); event Transfer(address indexed src, address indexed dst, uint256 amt); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address whom) external view returns (uint256); function allowance(address src, address dst) external view returns (uint256); function approve(address dst, uint256 amt) external returns (bool); function transfer(address dst, uint256 amt) external returns (bool); function transferFrom( address src, address dst, uint256 amt ) external returns (bool); } contract BTokenBase is BNum { mapping(address => uint256) internal _balance; mapping(address => mapping(address => uint256)) internal _allowance; uint256 internal _totalSupply; event Approval(address indexed src, address indexed dst, uint256 amt); event Transfer(address indexed src, address indexed dst, uint256 amt); function _mint(uint256 amt) internal { _balance[address(this)] = badd(_balance[address(this)], amt); _totalSupply = badd(_totalSupply, amt); emit Transfer(address(0), address(this), amt); } function _burn(uint256 amt) internal { require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[address(this)] = bsub(_balance[address(this)], amt); _totalSupply = bsub(_totalSupply, amt); emit Transfer(address(this), address(0), amt); } function _move( address src, address dst, uint256 amt ) internal { require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL"); _balance[src] = bsub(_balance[src], amt); _balance[dst] = badd(_balance[dst], amt); emit Transfer(src, dst, amt); } function _push(address to, uint256 amt) internal { _move(address(this), to, amt); } function _pull(address from, uint256 amt) internal { _move(from, address(this), amt); } } contract BToken is BTokenBase, IERC20 { uint8 private constant DECIMALS = 18; string private _name; string private _symbol; function _initializeToken(string memory name, string memory symbol) internal { require( bytes(_name).length == 0 && bytes(name).length != 0 && bytes(symbol).length != 0, "ERR_BTOKEN_INITIALIZED" ); _name = name; _symbol = symbol; } function name() external override view returns (string memory) { return _name; } function symbol() external override view returns (string memory) { return _symbol; } function decimals() external override view returns (uint8) { return DECIMALS; } function allowance(address src, address dst) external override view returns (uint256) { return _allowance[src][dst]; } function balanceOf(address whom) external override view returns (uint256) { return _balance[whom]; } function totalSupply() public override view returns (uint256) { return _totalSupply; } function approve(address dst, uint256 amt) external override returns (bool) { _allowance[msg.sender][dst] = amt; emit Approval(msg.sender, dst, amt); return true; } function increaseApproval(address dst, uint256 amt) external returns (bool) { _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt); emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function decreaseApproval(address dst, uint256 amt) external returns (bool) { uint256 oldValue = _allowance[msg.sender][dst]; if (amt > oldValue) { _allowance[msg.sender][dst] = 0; } else { _allowance[msg.sender][dst] = bsub(oldValue, amt); } emit Approval(msg.sender, dst, _allowance[msg.sender][dst]); return true; } function transfer(address dst, uint256 amt) external override returns (bool) { _move(msg.sender, dst, amt); return true; } function transferFrom( address src, address dst, uint256 amt ) external override returns (bool) { require( msg.sender == src || amt <= _allowance[src][msg.sender], "ERR_BTOKEN_BAD_CALLER" ); _move(src, dst, amt); if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) { _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt); emit Approval(msg.sender, dst, _allowance[src][msg.sender]); } return true; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; interface IIndexPool { /** * @dev Token record data structure * @param bound is token bound to pool * @param ready has token been initialized * @param lastDenormUpdate timestamp of last denorm change * @param denorm denormalized weight * @param desiredDenorm desired denormalized weight (used for incremental changes) * @param index index of address in tokens array * @param balance token balance */ struct Record { bool bound; bool ready; uint40 lastDenormUpdate; uint96 denorm; uint96 desiredDenorm; uint8 index; uint256 balance; } event LOG_SWAP( address indexed caller, address indexed tokenIn, address indexed tokenOut, uint256 tokenAmountIn, uint256 tokenAmountOut ); event LOG_JOIN( address indexed caller, address indexed tokenIn, uint256 tokenAmountIn ); event LOG_EXIT( address indexed caller, address indexed tokenOut, uint256 tokenAmountOut ); event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm); event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm); event LOG_TOKEN_REMOVED(address token); event LOG_TOKEN_ADDED( address indexed token, uint256 desiredDenorm, uint256 minimumBalance ); event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance); event LOG_TOKEN_READY(address indexed token); event LOG_PUBLIC_SWAP_TOGGLED(bool enabled); event LOG_MAX_TOKENS_UPDATED(uint256 maxPoolTokens); event LOG_SWAP_FEE_UPDATED(uint256 swapFee); function configure( address controller, string calldata name, string calldata symbol ) external; function initialize( address[] calldata tokens, uint256[] calldata balances, uint96[] calldata denorms, address tokenProvider, address unbindHandler, address exitFeeRecipient ) external; function setSwapFee(uint256 swapFee) external; function delegateCompLikeToken(address token, address delegatee) external; function setExitFeeRecipient(address) external; function setPublicSwap(bool enabled) external; function reweighTokens( address[] calldata tokens, uint96[] calldata desiredDenorms ) external; function reindexTokens( address[] calldata tokens, uint96[] calldata desiredDenorms, uint256[] calldata minimumBalances ) external; function setMinimumBalance(address token, uint256 minimumBalance) external; function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external; function joinswapExternAmountIn( address tokenIn, uint256 tokenAmountIn, uint256 minPoolAmountOut ) external returns (uint256/* poolAmountOut */); function joinswapPoolAmountOut( address tokenIn, uint256 poolAmountOut, uint256 maxAmountIn ) external returns (uint256/* tokenAmountIn */); function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external; function exitswapPoolAmountIn( address tokenOut, uint256 poolAmountIn, uint256 minAmountOut ) external returns (uint256/* tokenAmountOut */); function exitswapExternAmountOut( address tokenOut, uint256 tokenAmountOut, uint256 maxPoolAmountIn ) external returns (uint256/* poolAmountIn */); function gulp(address token) external; function swapExactAmountIn( address tokenIn, uint256 tokenAmountIn, address tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */); function swapExactAmountOut( address tokenIn, uint256 maxAmountIn, address tokenOut, uint256 tokenAmountOut, uint256 maxPrice ) external returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */); function isPublicSwap() external view returns (bool); function getSwapFee() external view returns (uint256/* swapFee */); function getController() external view returns (address); function getExitFeeRecipient() external view returns (address); function isBound(address t) external view returns (bool); function getNumTokens() external view returns (uint256); function getCurrentTokens() external view returns (address[] memory tokens); function getCurrentDesiredTokens() external view returns (address[] memory tokens); function getDenormalizedWeight(address token) external view returns (uint256/* denorm */); function getTokenRecord(address token) external view returns (Record memory record); function extrapolatePoolValueFromToken() external view returns (address/* token */, uint256/* extrapolatedValue */); function getTotalDenormalizedWeight() external view returns (uint256); function getBalance(address token) external view returns (uint256); function getMinimumBalance(address token) external view returns (uint256); function getUsedBalance(address token) external view returns (uint256); function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; interface ICompLikeToken { function delegate(address delegatee) external; }
{ "metadata": { "useLiteralContent": false }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newDenorm","type":"uint256"}],"name":"LOG_DENORM_UPDATED","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"desiredDenorm","type":"uint256"}],"name":"LOG_DESIRED_DENORM_SET","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_EXIT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"name":"LOG_JOIN","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPoolTokens","type":"uint256"}],"name":"LOG_MAX_TOKENS_UPDATED","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"minimumBalance","type":"uint256"}],"name":"LOG_MINIMUM_BALANCE_UPDATED","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"LOG_PUBLIC_SWAP_TOGGLED","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_SWAP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"LOG_SWAP_FEE_UPDATED","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"desiredDenorm","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minimumBalance","type":"uint256"}],"name":"LOG_TOKEN_ADDED","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"LOG_TOKEN_READY","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"LOG_TOKEN_REMOVED","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"VERSION_NUMBER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whom","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"configure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegateCompLikeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPoolAmountIn","type":"uint256"}],"name":"exitswapExternAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"exitswapPoolAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"extrapolatePoolValueFromToken","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentDesiredTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getDenormalizedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getMinimumBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"name":"getSpotPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSwapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenRecord","outputs":[{"components":[{"internalType":"bool","name":"bound","type":"bool"},{"internalType":"bool","name":"ready","type":"bool"},{"internalType":"uint40","name":"lastDenormUpdate","type":"uint40"},{"internalType":"uint96","name":"denorm","type":"uint96"},{"internalType":"uint96","name":"desiredDenorm","type":"uint96"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct IIndexPool.Record","name":"record","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDenormalizedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getUsedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"gulp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint96[]","name":"denorms","type":"uint96[]"},{"internalType":"address","name":"tokenProvider","type":"address"},{"internalType":"address","name":"unbindHandler","type":"address"},{"internalType":"address","name":"exitFeeRecipient","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"}],"name":"isBound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPublicSwap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"}],"name":"joinswapExternAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"}],"name":"joinswapPoolAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint96[]","name":"desiredDenorms","type":"uint96[]"},{"internalType":"uint256[]","name":"minimumBalances","type":"uint256[]"}],"name":"reindexTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint96[]","name":"desiredDenorms","type":"uint96[]"}],"name":"reweighTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"exitFeeRecipient","type":"address"}],"name":"setExitFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minimumBalance","type":"uint256"}],"name":"setMinimumBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setPublicSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"swapFee","type":"uint256"}],"name":"setSwapFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"swapExactAmountIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"swapExactAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615b8780620000216000396000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c80637c5e9ea41161015c578063a9059cbb116100ce578063d73dd62311610087578063d73dd6231461057a578063dd62ed3e1461058d578063f8b2cb4f146105a0578063f8b5db09146105b3578063f9f97c98146105c6578063fde924f7146105d95761028a565b8063a9059cbb14610529578063b02f0b731461053c578063c3f468101461054f578063cc77828d14610562578063cd2ed8fb1461056a578063d4cadf68146105725761028a565b806391bfa2bf1161012057806391bfa2bf146104ca578063936c3477146104dd578063948d8ce6146104e557806395d89b41146104f857806398836f0814610500578063a49c44d7146105165761028a565b80637c5e9ea4146104735780638025e303146104945780638201aa3f1461049c578063865bcccb146104af5780638c28cbe8146104b75761028a565b8063313ce567116102005780635d5e8ce7116101b95780635d5e8ce7146103f45780635db342771461040757806364c7d6611461041a578063661884631461043a5780636d06dfa01461044d57806370a08231146104605761028a565b8063313ce5671461038057806334e199071461039557806346ab38f1146103a857806349b59552146103bb5780634aa4e0b5146103ce5780634f69c0d4146103e15761028a565b806318160ddd1161025257806318160ddd1461031557806319f0f8491461031d57806323b872dd146103325780632b110c74146103455780632f37b624146103585780633018205f1461036b5761028a565b806302c967481461028f578063039209af146102b857806306fdde03146102cd578063095ea7b3146102e257806315e84af914610302575b600080fd5b6102a261029d366004614fb0565b6105e1565b6040516102af9190615a6c565b60405180910390f35b6102c06107bd565b6040516102af91906152f6565b6102d5610924565b6040516102af919061534e565b6102f56102f0366004614f37565b6109ba565b6040516102af9190615343565b6102a2610310366004614e43565b610a13565b6102a2610a9a565b61033061032b366004614eb7565b610aa0565b005b6102f5610340366004614e77565b610b9b565b610330610353366004614fe3565b610ccc565b6102f5610366366004614e28565b61113b565b61037361115d565b6040516102af91906152a5565b610388611171565b6040516102af9190615a83565b6103306103a33660046151e8565b611176565b6102a26103b6366004614fb0565b61121e565b6103306103c93660046151b0565b61139c565b6102a26103dc366004614e28565b611412565b6103306103ef366004615218565b61151f565b6103306104023660046150b1565b611718565b6102a2610415366004614fb0565b6117f4565b61042d610428366004614e28565b61199c565b6040516102af9190615a01565b6102f5610448366004614f37565b611a73565b6102a261045b366004614fb0565b611b3c565b6102a261046e366004614e28565b611cc6565b610486610481366004614f61565b611ce1565b6040516102af929190615a75565b6102a2611fd8565b6104866104aa366004614f61565b611fdd565b6103736122b0565b6103306104c5366004614e28565b6122bf565b6102a26104d8366004614e28565b612586565b6102a261269f565b6102a26104f3366004614e28565b6126cc565b6102d5612756565b6105086127b7565b6040516102af9291906152dd565b610330610524366004614f37565b6128bb565b6102f5610537366004614f37565b6129a3565b61033061054a366004615218565b6129b9565b61033061055d36600461511a565b612c84565b6102c061301d565b6102a26130a2565b6102a26130a8565b6102f5610588366004614f37565b6130d5565b6102a261059b366004614e43565b613149565b6102a26105ae366004614e28565b613174565b6103306105c1366004614e43565b6131dd565b6103306105d4366004614e28565b61326e565b6102f56132ba565b60055460009060ff16156106105760405162461bcd60e51b81526004016106079061564d565b60405180910390fd5b6005805460ff19166001179055610625614cc0565b61062e856132ca565b90506106538160c001516003670de0b6b3a76400008161064a57fe5b0460010161339f565b8411156106725760405162461bcd60e51b815260040161060790615672565b60006106998260c0015183606001516001600160601b0316600254600a5489600754613418565b9050806106b85760405162461bcd60e51b815260040161060790615478565b838111156106d85760405162461bcd60e51b8152600401610607906155f7565b6106e38633876134e2565b6106f18260c00151866135d1565b6001600160a01b038716600090815260096020526040902060010155610717828761360a565b600061072a826611c37937e0800061339f565b9050866001600160a01b0316336001600160a01b03167fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8860405161076f9190615a6c565b60405180910390a3610781338361379c565b61079361078e83836135d1565b6137a6565b600c546107a9906001600160a01b0316826137b2565b506005805460ff1916905595945050505050565b60055460609060ff16156107e35760405162461bcd60e51b81526004016106079061564d565b6060600880548060200260200160405190810160405280929190818152602001828054801561083b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161081d575b50505050509050805167ffffffffffffffff8111801561085a57600080fd5b50604051908082528060200260200182016040528015610884578160200160208202803683370190505b5091506000805b835181101561091d5760008382815181106108a257fe5b6020908102919091018101516001600160a01b03811660009081526009909252604090912054909150600160981b90046001600160601b03161561091457808584806001019550815181106108f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b5060010161088b565b5082525090565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109b05780601f10610985576101008083540402835291602001916109b0565b820191906000526020600020905b81548152906001019060200180831161099357829003601f168201915b5050505050905090565b3360008181526001602090815260408083206001600160a01b03871680855292528083208590555191929091600080516020615b3283398151915290610a01908690615a6c565b60405180910390a35060015b92915050565b60055460009060ff1615610a395760405162461bcd60e51b81526004016106079061564d565b610a41614cc0565b610a4a846137bc565b509050610a55614cc0565b610a5e846132ca565b9050610a918260c0015183606001516001600160601b03168360c0015184606001516001600160601b031660075461390a565b95945050505050565b60025490565b60055461010090046001600160a01b031615610ace5760405162461bcd60e51b815260040161060790615836565b6001600160a01b038516610af45760405162461bcd60e51b815260040161060790615931565b60058054610100600160a81b0319166101006001600160a01b038816021790556028670de0b6b3a764000004600755604080516020601f8601819004810282018101909252848152610b9491869086908190840183828082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061396f92505050565b5050505050565b6000336001600160a01b0385161480610bd757506001600160a01b03841660009081526001602090815260408083203384529091529020548211155b610bf35760405162461bcd60e51b8152600401610607906155c8565b610bfe8484846139e6565b336001600160a01b03851614801590610c3c57506001600160a01b038416600090815260016020908152604080832033845290915290205460001914155b15610cc2576001600160a01b0384166000908152600160209081526040808320338452909152902054610c6f90836135d1565b6001600160a01b038581166000908152600160209081526040808320338085529252918290208490559051918616929091600080516020615b3283398151915291610cb991615a6c565b60405180910390a35b5060019392505050565b60055461010090046001600160a01b03163314610cfb5760405162461bcd60e51b815260040161060790615381565b60085415610d1b5760405162461bcd60e51b815260040161060790615575565b876002811015610d3d5760405162461bcd60e51b815260040161060790615984565b600a811115610d5e5760405162461bcd60e51b8152600401610607906153fb565b8681148015610d6c57508481145b610d885760405162461bcd60e51b8152600401610607906157c5565b6000805b828110156110645760008c8c83818110610da257fe5b9050602002016020810190610db79190614e28565b90506000898984818110610dc757fe5b9050602002016020810190610ddc9190615262565b905060008c8c85818110610dec57fe5b9050602002013590506004670de0b6b3a764000081610e0757fe5b04826001600160601b03161015610e305760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b0383161115610e625760405162461bcd60e51b8152600401610607906154a1565b620f4240811015610e855760405162461bcd60e51b81526004016106079061551e565b6040518060e001604052806001151581526020016001151581526020014264ffffffffff168152602001836001600160601b03168152602001836001600160601b031681526020018560ff1681526020018281525060096000856001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160000160076101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160000160136101000a8154816001600160601b0302191690836001600160601b0316021790555060a082015181600001601f6101000a81548160ff021916908360ff16021790555060c082015181600101559050506008839080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b0316021790555061104c85836001600160601b0316613acf565b9450611059838a83613afb565b505050600101610d8c565b50680168d28e3f0028000081111561108e5760405162461bcd60e51b8152600401610607906154c9565b600a8190556006805460ff60a01b1916600160a01b1790556040517f40fc85fbff9305015298ba6fcee88b7e442a64cc803ddb889327680bbd62270a906110d790600190615343565b60405180910390a16110f168056bc75e2d63100000613b26565b6111048568056bc75e2d631000006137b2565b5050600680546001600160a01b039384166001600160a01b031991821617909155600c805492909316911617905550505050505050565b6001600160a01b03811660009081526009602052604090205460ff165b919050565b60055461010090046001600160a01b031690565b601290565b60055461010090046001600160a01b031633146111a55760405162461bcd60e51b815260040161060790615381565b64e8d4a5100081108015906111c2575067016345785d8a00008111155b6111de5760405162461bcd60e51b81526004016106079061595b565b60078190556040517fccfe595973efc7c1f6c29e31974d380470b9431d7770290185b7129419c7e63e90611213908390615a6c565b60405180910390a150565b60055460009060ff16156112445760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055611259614cc0565b611262856132ca565b9050600061128b8260c0015183606001516001600160601b0316600254600a5489600754613b2f565b9050838110156112ad5760405162461bcd60e51b8152600401610607906154f7565b6112c78260c001516003670de0b6b3a76400008161064a57fe5b8111156112e65760405162461bcd60e51b815260040161060790615672565b6112f18633836134e2565b6112ff8260c00151826135d1565b6001600160a01b038716600090815260096020526040902060010155611325828761360a565b6000611338866611c37937e0800061339f565b9050866001600160a01b0316336001600160a01b03167fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8460405161137d9190615a6c565b60405180910390a361138f338761379c565b61079361078e87836135d1565b60055461010090046001600160a01b031633146113cb5760405162461bcd60e51b815260040161060790615381565b6006805460ff60a01b1916600160a01b831515021790556040517f40fc85fbff9305015298ba6fcee88b7e442a64cc803ddb889327680bbd62270a90611213908390615343565b60055460009060ff16156114385760405162461bcd60e51b81526004016106079061564d565b611440614cc0565b506001600160a01b038216600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526114ec5760405162461bcd60e51b81526004016106079061569d565b80602001516115155750506001600160a01b0381166000908152600b6020526040902054611158565b60c0015192915050565b60055460ff16156115425760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff166115785760405162461bcd60e51b8152600401610607906156ef565b6000611582610a9a565b905060006115908583613bfe565b9050806115af5760405162461bcd60e51b815260040161060790615478565b60085483146115d05760405162461bcd60e51b8152600401610607906157c5565b60005b838110156116f3576000600882815481106115ea57fe5b6000918252602090912001546001600160a01b03169050611609614cc0565b6000611614836137bc565b915091506000611628868460c0015161339f565b9050806116475760405162461bcd60e51b815260040161060790615478565b88888681811061165357fe5b905060200201358111156116795760405162461bcd60e51b8152600401610607906155f7565b61168d84846116888585613acf565b613c92565b836001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a836040516116d09190615a6c565b60405180910390a36116e3843383613afb565b5050600190920191506115d39050565b506116fd85613b26565b61170733866137b2565b50506005805460ff19169055505050565b60055460ff161561173b5760405162461bcd60e51b81526004016106079061564d565b60058054600160ff19909116179081905561010090046001600160a01b031633146117785760405162461bcd60e51b815260040161060790615381565b8083146117975760405162461bcd60e51b8152600401610607906157c5565b60005b83811015611707576117ec8585838181106117b157fe5b90506020020160208101906117c69190614e28565b8484848181106117d257fe5b90506020020160208101906117e79190615262565b613e72565b60010161179a565b60055460009060ff161561181a5760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff166118505760405162461bcd60e51b8152600401610607906156ef565b611858614cc0565b6000611863866137bc565b9150915084600014156118885760405162461bcd60e51b8152600401610607906159dc565b6118a88260c001516002670de0b6b3a7640000816118a257fe5b0461339f565b8511156118c75760405162461bcd60e51b815260040161060790615423565b60006118ee8360c0015184606001516001600160601b0316600254600a548a600754613f8f565b9050848110156119105760405162461bcd60e51b8152600401610607906154f7565b61191f8784611688858a613acf565b866001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a886040516119629190615a6c565b60405180910390a361197381613b26565b61197d33826137b2565b611988873388613afb565b6005805460ff191690559695505050505050565b6119a4614cc0565b60055460ff16156119c75760405162461bcd60e51b81526004016106079061564d565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526111585760405162461bcd60e51b81526004016106079061569d565b3360009081526001602090815260408083206001600160a01b038616845290915281205480831115611ac8573360009081526001602090815260408083206001600160a01b0388168452909152812055611af7565b611ad281846135d1565b3360009081526001602090815260408083206001600160a01b03891684529091529020555b3360008181526001602090815260408083206001600160a01b038916808552925291829020549151909291600080516020615b3283398151915291610cb99190615a6c565b60055460009060ff1615611b625760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff16611b985760405162461bcd60e51b8152600401610607906156ef565b611ba0614cc0565b6000611bab866137bc565b915091506000611bd68360c0015184606001516001600160601b0316600254600a548a60075461402b565b905080611bf55760405162461bcd60e51b815260040161060790615478565b84811115611c155760405162461bcd60e51b8152600401610607906155f7565b611c2f8360c001516002670de0b6b3a7640000816118a257fe5b811115611c4e5760405162461bcd60e51b815260040161060790615423565b611c5d87846116888585613acf565b866001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a83604051611ca09190615a6c565b60405180910390a3611cb186613b26565b611cbb33876137b2565b611988873383613afb565b6001600160a01b031660009081526020819052604090205490565b600554600090819060ff1615611d095760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff16611d3f5760405162461bcd60e51b8152600401610607906156ef565b611d47614cc0565b6000611d52896137bc565b91509150611d5e614cc0565b611d67886132ca565b9050611d838160c001516003670de0b6b3a76400008161064a57fe5b871115611da25760405162461bcd60e51b815260040161060790615672565b6000611dd58460c0015185606001516001600160601b03168460c0015185606001516001600160601b031660075461390a565b905086811115611df75760405162461bcd60e51b815260040161060790615717565b6000611e2b8560c0015186606001516001600160601b03168560c0015186606001516001600160601b03168d6007546140c5565b90508a811115611e4d5760405162461bcd60e51b8152600401610607906155f7565b611e588c3383613afb565b611e638a338b6134e2565b611e6d8482613acf565b9350611e7a8c8686613c92565b846020015115611e8c5760c085018490525b611e9a8360c001518a6135d1565b60c084018190526001600160a01b038b16600090815260096020526040902060010155611ec7838b61360a565b6000611efa8660c0015187606001516001600160601b03168660c0015187606001516001600160601b031660075461390a565b905082811015611f1c5760405162461bcd60e51b815260040161060790615478565b88811115611f3c5760405162461bcd60e51b81526004016106079061580d565b611f46828b613bfe565b831115611f655760405162461bcd60e51b815260040161060790615478565b8a6001600160a01b03168d6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378858e604051611fb4929190615a75565b60405180910390a46005805460ff19169055909c909b509950505050505050505050565b600181565b600554600090819060ff16156120055760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff1661203b5760405162461bcd60e51b8152600401610607906156ef565b612043614cc0565b600061204e896137bc565b9150915061205a614cc0565b612063886132ca565b905061207f8360c001516002670de0b6b3a7640000816118a257fe5b89111561209e5760405162461bcd60e51b815260040161060790615423565b60006120d18460c0015185606001516001600160601b03168460c0015185606001516001600160601b031660075461390a565b9050868111156120f35760405162461bcd60e51b815260040161060790615717565b60006121278560c0015186606001516001600160601b03168560c0015186606001516001600160601b03168f600754614148565b9050888110156121495760405162461bcd60e51b8152600401610607906154f7565b6121548c338d613afb565b61215f8a33836134e2565b612169848c613acf565b93506121768c8686613c92565b8460200151156121885760c085018490525b6121968360c00151826135d1565b60c084018190526001600160a01b038b166000908152600960205260409020600101556121c3838b61360a565b60006121f68660c0015187606001516001600160601b03168660c0015187606001516001600160601b031660075461390a565b9050828110156122185760405162461bcd60e51b81526004016106079061544d565b888111156122385760405162461bcd60e51b81526004016106079061580d565b6122428c83613bfe565b8311156122615760405162461bcd60e51b815260040161060790615478565b8a6001600160a01b03168d6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d433788f86604051611fb4929190615a75565b600c546001600160a01b031690565b60055460ff16156122e25760405162461bcd60e51b81526004016106079061564d565b6005805460ff191660011790556001600160a01b03811660008181526009602052604080822090516370a0823160e01b81529092906370a082319061232b9030906004016152a5565b60206040518083038186803b15801561234357600080fd5b505afa158015612357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237b9190615200565b825490915060ff16156124fa578154610100900460ff166124d7576001600160a01b0383166000908152600b60205260409020548082106124d5576001600160a01b0384166000818152600b6020526040808220829055855461ff001916610100178655517ff7bb8e57ffdfd9a31e7580ee84f68757f44fb4a8a913f44520d22f2da1c955e59190a2600061241083836135d1565b9050600061241e8284613bfe565b9050600061243d6703782dace9d90000612438818561339f565b613acf565b8654600160381b600160981b031916600160381b6001600160601b0383169081029190911766ffffffffff00001916620100004264ffffffffff1602178855600a5491925061248c9190613acf565b600a5585546040516001600160a01b03891691600080516020615b12833981519152916124c991600160381b90046001600160601b031690615a91565b60405180910390a25050505b505b6001600160a01b0383166000908152600960205260409020600101819055612577565b6006546125129084906001600160a01b0316836134e2565b6006546040516360b8257960e11b81526001600160a01b039091169063c1704af29061254490869085906004016152dd565b600060405180830381600087803b15801561255e57600080fd5b505af1158015612572573d6000803e3d6000fd5b505050505b50506005805460ff1916905550565b60055460009060ff16156125ac5760405162461bcd60e51b81526004016106079061564d565b6125b4614cc0565b506001600160a01b038216600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526126605760405162461bcd60e51b81526004016106079061569d565b8060200151156126825760405162461bcd60e51b8152600401610607906157ea565b50506001600160a01b03166000908152600b602052604090205490565b60055460009060ff16156126c55760405162461bcd60e51b81526004016106079061564d565b50600a5490565b60055460009060ff16156126f25760405162461bcd60e51b81526004016106079061564d565b6001600160a01b03821660009081526009602052604090205460ff1661272a5760405162461bcd60e51b81526004016106079061569d565b506001600160a01b0316600090815260096020526040902054600160381b90046001600160601b031690565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109b05780601f10610985576101008083540402835291602001916109b0565b600554600090819060ff16156127df5760405162461bcd60e51b81526004016106079061564d565b6008546000908190815b8181101561289057600881815481106127fe57fe5b60009182526020808320909101546001600160a01b03168083526009909152604090912080549195509060ff61010090910416801561284d57508054600160981b90046001600160601b031615155b15612887576001810154600a54825461287f929161287a91600160381b90046001600160601b0316613bfe565b61339f565b935050612890565b506001016127e9565b50600082116128b15760405162461bcd60e51b8152600401610607906153ad565b5090925090509091565b60055461010090046001600160a01b031633146128ea5760405162461bcd60e51b815260040161060790615381565b6001600160a01b0382166000908152600960205260409020805460ff166129235760405162461bcd60e51b81526004016106079061569d565b8054610100900460ff161561294a5760405162461bcd60e51b8152600401610607906157ea565b6001600160a01b0383166000908152600b602052604090819020839055517e0c7a55677231b335e6dea005fa240ac2aeafbd62f188372a7d66892b722c529061299690859085906152dd565b60405180910390a1505050565b60006129b03384846139e6565b50600192915050565b60055460ff16156129dc5760405162461bcd60e51b81526004016106079061564d565b6005805460ff191660011790556008548114612a0a5760405162461bcd60e51b8152600401610607906157c5565b6000612a14610a9a565b90506000612a29856611c37937e0800061339f565b90506000612a3786836135d1565b90506000612a458285613bfe565b905080612a645760405162461bcd60e51b815260040161060790615478565b612a6e338861379c565b600c54612a84906001600160a01b0316846137b2565b612a8d826137a6565b60005b85811015612c7057600060088281548110612aa757fe5b6000918252602090912001546001600160a01b03169050612ac6614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158352610100820481161580159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c0830152612c34576000612b6a858360c0015161339f565b905080612b895760405162461bcd60e51b815260040161060790615478565b898985818110612b9557fe5b90506020020135811015612bbb5760405162461bcd60e51b8152600401610607906154f7565b612bc98260c00151826135d1565b6001600160a01b0384166000818152600960205260409081902060010192909255905133907fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed90612c1b908590615a6c565b60405180910390a3612c2e8333836134e2565b50612c66565b888884818110612c4057fe5b90506020020135600014612c665760405162461bcd60e51b8152600401610607906156c4565b5050600101612a90565b50506005805460ff19169055505050505050565b60055460ff1615612ca75760405162461bcd60e51b81526004016106079061564d565b60058054600160ff19909116179081905561010090046001600160a01b03163314612ce45760405162461bcd60e51b815260040161060790615381565b8285148015612cf257508085145b612d0e5760405162461bcd60e51b8152600401610607906157c5565b60085460608167ffffffffffffffff81118015612d2a57600080fd5b50604051908082528060200260200182016040528015612d54578160200160208202803683370190505b50905060608767ffffffffffffffff81118015612d7057600080fd5b50604051908082528060200260200182016040528015612daa57816020015b612d97614cc0565b815260200190600190039081612d8f5790505b50905060005b88811015612ee557600960008b8b84818110612dc857fe5b9050602002016020810190612ddd9190614e28565b6001600160a01b031681526020808201929092526040908101600020815160e081018352815460ff808216151583526101008204811615159583019590955264ffffffffff62010000820416938201939093526001600160601b03600160381b840481166060830152600160981b8404166080820152600160f81b90920490921660a082015260019091015460c08201528251839083908110612e7c57fe5b6020026020010181905250818181518110612e9357fe5b60200260200101516000015115612edd57600183838381518110612eb357fe5b602002602001015160a0015160ff1681518110612ecc57fe5b911515602092830291909101909101525b600101612db0565b5060005b83811015612f3b57828181518110612efd57fe5b6020026020010151612f3357612f3360088281548110612f1957fe5b60009182526020822001546001600160a01b031690613e72565b600101612ee9565b5060005b888110156130075760008a8a83818110612f5557fe5b9050602002016020810190612f6a9190614e28565b90506000898984818110612f7a57fe5b9050602002016020810190612f8f9190615262565b90506703782dace9d900006001600160601b0382161015612fb557506703782dace9d900005b838381518110612fc157fe5b602002602001015160000151612ff357612fee82898986818110612fe157fe5b90506020020135836141c9565b612ffd565b612ffd8282613e72565b5050600101612f3f565b50506005805460ff191690555050505050505050565b60055460609060ff16156130435760405162461bcd60e51b81526004016106079061564d565b60088054806020026020016040519081016040528092919081815260200182805480156109b057602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161307b575050505050905090565b60085490565b60055460009060ff16156130ce5760405162461bcd60e51b81526004016106079061564d565b5060075490565b3360009081526001602090815260408083206001600160a01b03861684529091528120546131039083613acf565b3360008181526001602090815260408083206001600160a01b03891680855292529182902084905590519092600080516020615b3283398151915291610a019190615a6c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60055460009060ff161561319a5760405162461bcd60e51b81526004016106079061564d565b6001600160a01b0382166000908152600960205260409020805460ff166131d35760405162461bcd60e51b81526004016106079061569d565b6001015492915050565b60055461010090046001600160a01b0316331461320c5760405162461bcd60e51b815260040161060790615381565b6040516317066a5760e21b81526001600160a01b03831690635c19a95c906132389084906004016152a5565b600060405180830381600087803b15801561325257600080fd5b505af1158015613266573d6000803e3d6000fd5b505050505050565b600c546001600160a01b031633146132985760405162461bcd60e51b81526004016106079061576c565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600654600160a01b900460ff1690565b6132d2614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c083015261337e5760405162461bcd60e51b81526004016106079061569d565b80602001516111585760405162461bcd60e51b8152600401610607906156c4565b60008282028315806133b95750828482816133b657fe5b04145b6133d55760405162461bcd60e51b81526004016106079061579b565b6706f05b59d3b200008101818110156134005760405162461bcd60e51b81526004016106079061579b565b6000670de0b6b3a7640000825b049695505050505050565b6000806134258786613bfe565b9050600061343b670de0b6b3a7640000836135d1565b90506000613449828661339f565b9050600061346887613463670de0b6b3a7640000856135d1565b613bfe565b905060006134768c836135d1565b90506000613484828e613bfe565b9050600061349282886144a9565b905060006134a0828e61339f565b905060006134ae8e836135d1565b90506134cd81613463670de0b6b3a76400006611c37937e080006135d1565b99505050505050505050509695505050505050565b60006060846001600160a01b031663a9059cbb60e01b858560405160240161350b9291906152dd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516135499190615289565b6000604051808303816000865af19150503d8060008114613586576040519150601f19603f3d011682016040523d82523d6000602084013e61358b565b606091505b50915091508180156135b55750805115806135b55750808060200190518101906135b591906151cc565b610b945760405162461bcd60e51b8152600401610607906158b3565b60008060006135e0858561455c565b9150915080156136025760405162461bcd60e51b8152600401610607906158dc565b509392505050565b81608001516001600160601b031682606001516001600160601b031611158061363557508160200151155b8061364e5750610e10826040015164ffffffffff164203105b1561365857613798565b6060820151608083015160006136816001600160601b0384166064670de0b6b3a76400006118a2565b905060006136a1846001600160601b0316846001600160601b03166135d1565b9050818111156136c4576136be846001600160601b0316836135d1565b92508190505b6703782dace9d900006001600160601b038416116136fe57600a54600093506136ed90846135d1565b600a556136f985614581565b613266565b61370a600a54826135d1565b600a556001600160601b038316606087018190526001600160a01b038616600081815260096020526040908190208054600160381b600160981b031916600160381b9094029390931766ffffffffff00001916620100004264ffffffffff1602179092559051600080516020615b128339815191529061378b908690615a91565b60405180910390a2505050505b5050565b61379882826148c3565b6137af816148ce565b50565b6137988282614977565b6137c4614cc0565b506001600160a01b0381166000908152600960209081526040808320815160e081018352815460ff80821615158084526101008304821615159684019690965264ffffffffff62010000830416948301949094526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490921660a08301526001015460c082015291906138715760405162461bcd60e51b81526004016106079061569d565b5060c08101516020820151613905576001600160a01b0383166000908152600b602052604081205460c084018190526138b8906138ae90846135d1565b8460c00151613bfe565b905060006138dc600a6004670de0b6b3a76400005b04816138d557fe5b048361339f565b90506138f46004670de0b6b3a76400005b0482613acf565b6001600160601b0316606085015250505b915091565b6000806139178787613bfe565b905060006139258686613bfe565b905060006139338383613bfe565b90506000613955670de0b6b3a7640000613463670de0b6b3a7640000896135d1565b9050613961828261339f565b9a9950505050505050505050565b600354600260001961010060018416150201909116041580156139925750815115155b801561399e5750805115155b6139ba5760405162461bcd60e51b81526004016106079061561d565b81516139cd906003906020850190614cfc565b5080516139e1906004906020840190614cfc565b505050565b6001600160a01b038316600090815260208190526040902054811115613a1e5760405162461bcd60e51b815260040161060790615547565b6001600160a01b038316600090815260208190526040902054613a4190826135d1565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613a709082613acf565b6001600160a01b0380841660008181526020819052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613ac2908590615a6c565b60405180910390a3505050565b600082820183811015613af45760405162461bcd60e51b815260040161060790615907565b9392505050565b60006060846001600160a01b03166323b872dd60e01b85308660405160240161350b939291906152b9565b6137af81614982565b600080613b3c8786613bfe565b90506000613b5d8561287a670de0b6b3a76400006611c37937e080006135d1565b90506000613b6b88836135d1565b90506000613b79828a613bfe565b90506000613b9882613b93670de0b6b3a764000088613bfe565b6144a9565b90506000613ba6828e61339f565b90506000613bb48e836135d1565b90506000613bd3613bcd670de0b6b3a76400008a6135d1565b8b61339f565b9050613beb8261287a670de0b6b3a7640000846135d1565b9f9e505050505050505050505050505050565b600081613c1d5760405162461bcd60e51b81526004016106079061585e565b670de0b6b3a76400008302831580613c455750670de0b6b3a7640000848281613c4257fe5b04145b613c615760405162461bcd60e51b81526004016106079061559e565b60028304810181811015613c875760405162461bcd60e51b81526004016106079061559e565b600084828161340d57fe5b8160200151613e45578160c001518110613dee576001600160a01b0383166000818152600b6020908152604080832083905560098252808320805461ff001916610100179055600191860191909152517ff7bb8e57ffdfd9a31e7580ee84f68757f44fb4a8a913f44520d22f2da1c955e59190a26000613d16828460c001516135d1565b90506000613d28828560c00151613bfe565b9050613d406703782dace9d90000612438818461339f565b6001600160601b03908116606086018181526001600160a01b03881660009081526009602052604090208054600160381b600160981b031916600160381b9093029290921766ffffffffff00001916620100004264ffffffffff160217909155600a549051613daf9216613acf565b600a5560608401516040516001600160a01b03871691600080516020615b1283398151915291613ddf9190615a91565b60405180910390a25050613e40565b6000613e016138ae8460c00151846135d1565b90506000613e1a600a6004670de0b6b3a76400006138cd565b9050613e2f6004670de0b6b3a76400006138ed565b6001600160601b0316606085015250505b613e4f565b613e4f82846149f1565b6001600160a01b0390921660009081526009602052604090206001019190915550565b6001600160a01b0382166000908152600960205260409020805460ff16613eab5760405162461bcd60e51b81526004016106079061569d565b6703782dace9d900006001600160601b038316101580613ed257506001600160601b038216155b613eee5760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b0383161115613f205760405162461bcd60e51b8152600401610607906154a1565b80546bffffffffffffffffffffffff60981b1916600160981b6001600160601b038416021781556040516001600160a01b038416907fc7ea88f3376e27ce6ebc2025310023327f743a8377d438258c36b166dd8b298390613f82908590615a91565b60405180910390a2505050565b600080613f9c8786613bfe565b90506000613fbb613fb5670de0b6b3a7640000846135d1565b8561339f565b90506000613fd58661287a670de0b6b3a7640000856135d1565b90506000613fe38b83613acf565b90506000613ff1828d613bfe565b90506000613fff82876144a9565b9050600061400d828d61339f565b9050614019818d6135d1565b9e9d5050505050505050505050505050565b6000806140388786613bfe565b905060006140468786613acf565b905060006140548289613bfe565b9050600061406a670de0b6b3a764000085613bfe565b9050600061407883836144a9565b90506000614086828e61339f565b90506000614094828f6135d1565b905060006140ad613bcd670de0b6b3a76400008a6135d1565b9050613beb82613463670de0b6b3a7640000846135d1565b6000806140d28588613bfe565b905060006140e087866135d1565b905060006140ee8883613bfe565b905060006140fc82856144a9565b905061411081670de0b6b3a76400006135d1565b9050614124670de0b6b3a7640000876135d1565b94506141396141338c8361339f565b86613bfe565b9b9a5050505050505050505050565b6000806141558786613bfe565b9050600061416b670de0b6b3a7640000856135d1565b9050614177858261339f565b905060006141898a6134638c85613acf565b9050600061419782856144a9565b905060006141ad670de0b6b3a7640000836135d1565b90506141b98a8261339f565b9c9b505050505050505050505050565b6001600160a01b03831660009081526009602052604090205460ff16156142025760405162461bcd60e51b8152600401610607906153d5565b6703782dace9d900006001600160601b03821610156142335760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b03821611156142655760405162461bcd60e51b8152600401610607906154a1565b620f42408210156142885760405162461bcd60e51b81526004016106079061551e565b6040518060e00160405280600115158152602001600015158152602001600064ffffffffff16815260200160006001600160601b03168152602001826001600160601b0316815260200160088054905060ff168152602001600081525060096000856001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160000160076101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160000160136101000a8154816001600160601b0302191690836001600160601b0316021790555060a082015181600001601f6101000a81548160ff021916908360ff16021790555060c082015181600101559050506008839080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600b6000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550826001600160a01b03167fb2daf560899f6307b318aecfb57eb2812c488da4a4c1cad2019b482fa63294ed8284604051613f82929190615aa5565b600060018310156144cc5760405162461bcd60e51b815260040161060790615884565b671bc16d674ec7ffff8311156144f45760405162461bcd60e51b8152600401610607906159ac565b60006144ff83614b62565b9050600061450d84836135d1565b905060006145238661451e85614b7d565b614b8b565b905081614534579250610a0d915050565b600061454587846305f5e100614be2565b9050614551828261339f565b979650505050505050565b600080828410614572575050808203600061457a565b505081810360015b9250929050565b614589614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff808216151583526101008204811615159483019490945264ffffffffff62010000820416948201949094526001600160601b03600160381b850481166060830152600160981b8504166080820152600160f81b90930490911660a0830181905260019091015460c08301819052600854909190600019018082146146e7576008818154811061463d57fe5b600091825260209091200154600880546001600160a01b03909216918490811061466357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160096000600885815481106146a357fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020805460ff92909216600160f81b026001600160f81b039092169190911790555b60088054806146f257fe5b60008281526020808220600019908401810180546001600160a01b03191690559092019092556040805160e081018252838152808301848152818301858152606083018681526080840187815260a0850188815260c086018981526001600160a01b038f81168b52600990995296909820945185549451935192519151985160ff199095169015151761ff001916610100931515939093029290921766ffffffffff000019166201000064ffffffffff9092169190910217600160381b600160981b031916600160381b6001600160601b0392831602176bffffffffffffffffffffffff60981b1916600160981b9190961602949094176001600160f81b0316600160f81b60ff90951694909402939093178355516001929092019190915560065461482191879116856134e2565b6006546040516360b8257960e11b81526001600160a01b039091169063c1704af29061485390889087906004016152dd565b600060405180830381600087803b15801561486d57600080fd5b505af1158015614881573d6000803e3d6000fd5b505050507f12a8262eb28ee8a8c11e6cf411b3af6ce5bea42abb36e051bf0a65ae602d52ec856040516148b491906152a5565b60405180910390a15050505050565b6137988230836139e6565b306000908152602081905260409020548111156148fd5760405162461bcd60e51b815260040161060790615547565b3060009081526020819052604090205461491790826135d1565b3060009081526020819052604090205560025461493490826135d1565b60025560405160009030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061496c908590615a6c565b60405180910390a350565b6137983083836139e6565b3060009081526020819052604090205461499c9082613acf565b306000908152602081905260409020556002546149b99082613acf565b60025560405130906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061496c908590615a6c565b81608001516001600160601b031682606001516001600160601b0316101580614a1c57508160200151155b80614a355750610e10826040015164ffffffffff164203105b15614a3f57613798565b606082015160808301516000614a686001600160601b0384166064670de0b6b3a76400006118a2565b90506000614a88836001600160601b0316856001600160601b03166135d1565b905081811115614aab57614aa5846001600160601b031683613acf565b92508190505b614ab7600a5482613acf565b600a819055680168d28e3f002800001015614ae45760405162461bcd60e51b8152600401610607906154c9565b6001600160601b038316606087018190526001600160a01b038616600081815260096020526040908190208054600160381b600160981b031916600160381b9094029390931766ffffffffff00001916620100004264ffffffffff1602179092559051600080516020615b128339815191529061378b908690615a91565b6000670de0b6b3a7640000614b7683614b7d565b0292915050565b670de0b6b3a7640000900490565b60008060028306614ba457670de0b6b3a7640000614ba6565b835b90506002830492505b8215613af457614bbf848561339f565b93506002830615614bd757614bd4818561339f565b90505b600283049250614baf565b6000828180614bf987670de0b6b3a764000061455c565b9092509050670de0b6b3a764000080600060015b888410614cb1576000670de0b6b3a764000082029050600080614c418a614c3c85670de0b6b3a76400006135d1565b61455c565b91509150614c538761287a848c61339f565b9650614c5f8784613bfe565b965086614c6e57505050614cb1565b8715614c78579315935b8015614c82579315935b8415614c9957614c9286886135d1565b9550614ca6565b614ca38688613acf565b95505b505050600101614c0d565b50909998505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614d3d57805160ff1916838001178555614d6a565b82800160010185558215614d6a579182015b82811115614d6a578251825591602001919060010190614d4f565b50614d76929150614d7a565b5090565b5b80821115614d765760008155600101614d7b565b80356001600160a01b0381168114610a0d57600080fd5b60008083601f840112614db7578182fd5b50813567ffffffffffffffff811115614dce578182fd5b602083019150836020808302850101111561457a57600080fd5b60008083601f840112614df9578182fd5b50813567ffffffffffffffff811115614e10578182fd5b60208301915083602082850101111561457a57600080fd5b600060208284031215614e39578081fd5b613af48383614d8f565b60008060408385031215614e55578081fd5b614e5f8484614d8f565b9150614e6e8460208501614d8f565b90509250929050565b600080600060608486031215614e8b578081fd5b8335614e9681615aee565b92506020840135614ea681615aee565b929592945050506040919091013590565b600080600080600060608688031215614ece578081fd5b8535614ed981615aee565b9450602086013567ffffffffffffffff80821115614ef5578283fd5b614f0189838a01614de8565b90965094506040880135915080821115614f19578283fd5b50614f2688828901614de8565b969995985093965092949392505050565b60008060408385031215614f49578182fd5b614f538484614d8f565b946020939093013593505050565b600080600080600060a08688031215614f78578081fd5b614f828787614d8f565b945060208601359350614f988760408801614d8f565b94979396509394606081013594506080013592915050565b600080600060608486031215614fc4578283fd5b614fce8585614d8f565b95602085013595506040909401359392505050565b600080600080600080600080600060c08a8c031215615000578384fd5b893567ffffffffffffffff80821115615017578586fd5b6150238d838e01614da6565b909b50995060208c013591508082111561503b578586fd5b6150478d838e01614da6565b909950975060408c013591508082111561505f578586fd5b5061506c8c828d01614da6565b90965094505060608a013561508081615aee565b925060808a013561509081615aee565b915060a08a01356150a081615aee565b809150509295985092959850929598565b600080600080604085870312156150c6578384fd5b843567ffffffffffffffff808211156150dd578586fd5b6150e988838901614da6565b90965094506020870135915080821115615101578384fd5b5061510e87828801614da6565b95989497509550505050565b60008060008060008060608789031215615132578384fd5b863567ffffffffffffffff80821115615149578586fd5b6151558a838b01614da6565b9098509650602089013591508082111561516d578586fd5b6151798a838b01614da6565b90965094506040890135915080821115615191578384fd5b5061519e89828a01614da6565b979a9699509497509295939492505050565b6000602082840312156151c1578081fd5b8135613af481615b03565b6000602082840312156151dd578081fd5b8151613af481615b03565b6000602082840312156151f9578081fd5b5035919050565b600060208284031215615211578081fd5b5051919050565b60008060006040848603121561522c578081fd5b83359250602084013567ffffffffffffffff811115615249578182fd5b61525586828701614da6565b9497909650939450505050565b600060208284031215615273578081fd5b81356001600160601b0381168114613af4578182fd5b6000825161529b818460208701615abe565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156153375783516001600160a01b031683529284019291840191600101615312565b50909695505050505050565b901515815260200190565b600060208252825180602084015261536d816040850160208701615abe565b601f01601f19169190910160400192915050565b60208082526012908201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604082015260600190565b6020808252600e908201526d4552525f4e4f4e455f524541445960901b604082015260600190565b6020808252600c908201526b11549497d254d7d093d5539160a21b604082015260600190565b6020808252600e908201526d4552525f4d41585f544f4b454e5360901b604082015260600190565b60208082526010908201526f4552525f4d41585f494e5f524154494f60801b604082015260600190565b60208082526011908201527022a9292fa6a0aa242fa0a8282927ac2f9960791b604082015260600190565b6020808252600f908201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604082015260600190565b6020808252600e908201526d11549497d3505617d5d15251d21560921b604082015260600190565b60208082526014908201527311549497d3505617d513d5105317d5d15251d21560621b604082015260600190565b6020808252600d908201526c11549497d31253525517d3d555609a1b604082015260600190565b6020808252600f908201526e4552525f4d494e5f42414c414e434560881b604082015260600190565b60208082526014908201527311549497d25394d551919250d251539517d0905360621b604082015260600190565b6020808252600f908201526e11549497d253925512505312569151608a1b604082015260600190565b60208082526010908201526f11549497d1125597d25395115493905360821b604082015260600190565b60208082526015908201527422a9292fa12a27a5a2a72fa120a22fa1a0a62622a960591b604082015260600190565b6020808252600c908201526b22a9292fa624a6a4aa2fa4a760a11b604082015260600190565b60208082526016908201527511549497d09513d2d15397d25392551250531256915160521b604082015260600190565b6020808252600b908201526a4552525f5245454e54525960a81b604082015260600190565b6020808252601190820152704552525f4d41585f4f55545f524154494f60781b604082015260600190565b6020808252600d908201526c11549497d393d517d093d55391609a1b604082015260600190565b6020808252601190820152704552525f4f55545f4e4f545f524541445960781b604082015260600190565b6020808252600e908201526d4552525f4e4f545f5055424c494360901b604082015260600190565b6020808252601390820152724552525f4241445f4c494d49545f505249434560681b604082015260600190565b6020808252600e908201526d11549497d3525397d5d15251d21560921b604082015260600190565b60208082526015908201527411549497d393d517d1915157d49150d25412515395605a1b604082015260600190565b60208082526010908201526f4552525f4d554c5f4f564552464c4f5760801b604082015260600190565b6020808252600b908201526a22a9292fa0a9292fa622a760a91b604082015260600190565b6020808252600990820152684552525f524541445960b81b604082015260600190565b6020808252600f908201526e4552525f4c494d49545f505249434560881b604082015260600190565b6020808252600e908201526d11549497d0d3d3919251d554915160921b604082015260600190565b6020808252600c908201526b4552525f4449565f5a45524f60a01b604082015260600190565b6020808252601590820152744552525f42504f575f424153455f544f4f5f4c4f5760581b604082015260600190565b6020808252600f908201526e4552525f45524332305f46414c534560881b604082015260600190565b6020808252601190820152704552525f5355425f554e444552464c4f5760781b604082015260600190565b60208082526010908201526f4552525f4144445f4f564552464c4f5760801b604082015260600190565b60208082526010908201526f4552525f4e554c4c5f4144445245535360801b604082015260600190565b6020808252600f908201526e4552525f494e56414c49445f46454560881b604082015260600190565b6020808252600e908201526d4552525f4d494e5f544f4b454e5360901b604082015260600190565b60208082526016908201527508aa4a4be84a09eaebe8482a68abea89e9ebe90928e960531b604082015260600190565b6020808252600b908201526a22a9292fad22a927afa4a760a91b604082015260600190565b600060e08201905082511515825260208301511515602083015264ffffffffff604084015116604083015260608301516001600160601b038082166060850152806080860151166080850152505060ff60a08401511660a083015260c083015160c083015292915050565b90815260200190565b918252602082015260400190565b60ff91909116815260200190565b6001600160601b0391909116815260200190565b6001600160601b03929092168252602082015260400190565b60005b83811015615ad9578181015183820152602001615ac1565b83811115615ae8576000848401525b50505050565b6001600160a01b03811681146137af57600080fd5b80151581146137af57600080fdfe21b12aed5d425f5675450ffeeae01039085e5323974c3099e1828155d9b51e778c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a264697066735822122018b2550a0d179afba2d654006db034e06e0e741847346b333f104cd911ac2cd264736f6c634300060c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061028a5760003560e01c80637c5e9ea41161015c578063a9059cbb116100ce578063d73dd62311610087578063d73dd6231461057a578063dd62ed3e1461058d578063f8b2cb4f146105a0578063f8b5db09146105b3578063f9f97c98146105c6578063fde924f7146105d95761028a565b8063a9059cbb14610529578063b02f0b731461053c578063c3f468101461054f578063cc77828d14610562578063cd2ed8fb1461056a578063d4cadf68146105725761028a565b806391bfa2bf1161012057806391bfa2bf146104ca578063936c3477146104dd578063948d8ce6146104e557806395d89b41146104f857806398836f0814610500578063a49c44d7146105165761028a565b80637c5e9ea4146104735780638025e303146104945780638201aa3f1461049c578063865bcccb146104af5780638c28cbe8146104b75761028a565b8063313ce567116102005780635d5e8ce7116101b95780635d5e8ce7146103f45780635db342771461040757806364c7d6611461041a578063661884631461043a5780636d06dfa01461044d57806370a08231146104605761028a565b8063313ce5671461038057806334e199071461039557806346ab38f1146103a857806349b59552146103bb5780634aa4e0b5146103ce5780634f69c0d4146103e15761028a565b806318160ddd1161025257806318160ddd1461031557806319f0f8491461031d57806323b872dd146103325780632b110c74146103455780632f37b624146103585780633018205f1461036b5761028a565b806302c967481461028f578063039209af146102b857806306fdde03146102cd578063095ea7b3146102e257806315e84af914610302575b600080fd5b6102a261029d366004614fb0565b6105e1565b6040516102af9190615a6c565b60405180910390f35b6102c06107bd565b6040516102af91906152f6565b6102d5610924565b6040516102af919061534e565b6102f56102f0366004614f37565b6109ba565b6040516102af9190615343565b6102a2610310366004614e43565b610a13565b6102a2610a9a565b61033061032b366004614eb7565b610aa0565b005b6102f5610340366004614e77565b610b9b565b610330610353366004614fe3565b610ccc565b6102f5610366366004614e28565b61113b565b61037361115d565b6040516102af91906152a5565b610388611171565b6040516102af9190615a83565b6103306103a33660046151e8565b611176565b6102a26103b6366004614fb0565b61121e565b6103306103c93660046151b0565b61139c565b6102a26103dc366004614e28565b611412565b6103306103ef366004615218565b61151f565b6103306104023660046150b1565b611718565b6102a2610415366004614fb0565b6117f4565b61042d610428366004614e28565b61199c565b6040516102af9190615a01565b6102f5610448366004614f37565b611a73565b6102a261045b366004614fb0565b611b3c565b6102a261046e366004614e28565b611cc6565b610486610481366004614f61565b611ce1565b6040516102af929190615a75565b6102a2611fd8565b6104866104aa366004614f61565b611fdd565b6103736122b0565b6103306104c5366004614e28565b6122bf565b6102a26104d8366004614e28565b612586565b6102a261269f565b6102a26104f3366004614e28565b6126cc565b6102d5612756565b6105086127b7565b6040516102af9291906152dd565b610330610524366004614f37565b6128bb565b6102f5610537366004614f37565b6129a3565b61033061054a366004615218565b6129b9565b61033061055d36600461511a565b612c84565b6102c061301d565b6102a26130a2565b6102a26130a8565b6102f5610588366004614f37565b6130d5565b6102a261059b366004614e43565b613149565b6102a26105ae366004614e28565b613174565b6103306105c1366004614e43565b6131dd565b6103306105d4366004614e28565b61326e565b6102f56132ba565b60055460009060ff16156106105760405162461bcd60e51b81526004016106079061564d565b60405180910390fd5b6005805460ff19166001179055610625614cc0565b61062e856132ca565b90506106538160c001516003670de0b6b3a76400008161064a57fe5b0460010161339f565b8411156106725760405162461bcd60e51b815260040161060790615672565b60006106998260c0015183606001516001600160601b0316600254600a5489600754613418565b9050806106b85760405162461bcd60e51b815260040161060790615478565b838111156106d85760405162461bcd60e51b8152600401610607906155f7565b6106e38633876134e2565b6106f18260c00151866135d1565b6001600160a01b038716600090815260096020526040902060010155610717828761360a565b600061072a826611c37937e0800061339f565b9050866001600160a01b0316336001600160a01b03167fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8860405161076f9190615a6c565b60405180910390a3610781338361379c565b61079361078e83836135d1565b6137a6565b600c546107a9906001600160a01b0316826137b2565b506005805460ff1916905595945050505050565b60055460609060ff16156107e35760405162461bcd60e51b81526004016106079061564d565b6060600880548060200260200160405190810160405280929190818152602001828054801561083b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161081d575b50505050509050805167ffffffffffffffff8111801561085a57600080fd5b50604051908082528060200260200182016040528015610884578160200160208202803683370190505b5091506000805b835181101561091d5760008382815181106108a257fe5b6020908102919091018101516001600160a01b03811660009081526009909252604090912054909150600160981b90046001600160601b03161561091457808584806001019550815181106108f357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b5060010161088b565b5082525090565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109b05780601f10610985576101008083540402835291602001916109b0565b820191906000526020600020905b81548152906001019060200180831161099357829003601f168201915b5050505050905090565b3360008181526001602090815260408083206001600160a01b03871680855292528083208590555191929091600080516020615b3283398151915290610a01908690615a6c565b60405180910390a35060015b92915050565b60055460009060ff1615610a395760405162461bcd60e51b81526004016106079061564d565b610a41614cc0565b610a4a846137bc565b509050610a55614cc0565b610a5e846132ca565b9050610a918260c0015183606001516001600160601b03168360c0015184606001516001600160601b031660075461390a565b95945050505050565b60025490565b60055461010090046001600160a01b031615610ace5760405162461bcd60e51b815260040161060790615836565b6001600160a01b038516610af45760405162461bcd60e51b815260040161060790615931565b60058054610100600160a81b0319166101006001600160a01b038816021790556028670de0b6b3a764000004600755604080516020601f8601819004810282018101909252848152610b9491869086908190840183828082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061396f92505050565b5050505050565b6000336001600160a01b0385161480610bd757506001600160a01b03841660009081526001602090815260408083203384529091529020548211155b610bf35760405162461bcd60e51b8152600401610607906155c8565b610bfe8484846139e6565b336001600160a01b03851614801590610c3c57506001600160a01b038416600090815260016020908152604080832033845290915290205460001914155b15610cc2576001600160a01b0384166000908152600160209081526040808320338452909152902054610c6f90836135d1565b6001600160a01b038581166000908152600160209081526040808320338085529252918290208490559051918616929091600080516020615b3283398151915291610cb991615a6c565b60405180910390a35b5060019392505050565b60055461010090046001600160a01b03163314610cfb5760405162461bcd60e51b815260040161060790615381565b60085415610d1b5760405162461bcd60e51b815260040161060790615575565b876002811015610d3d5760405162461bcd60e51b815260040161060790615984565b600a811115610d5e5760405162461bcd60e51b8152600401610607906153fb565b8681148015610d6c57508481145b610d885760405162461bcd60e51b8152600401610607906157c5565b6000805b828110156110645760008c8c83818110610da257fe5b9050602002016020810190610db79190614e28565b90506000898984818110610dc757fe5b9050602002016020810190610ddc9190615262565b905060008c8c85818110610dec57fe5b9050602002013590506004670de0b6b3a764000081610e0757fe5b04826001600160601b03161015610e305760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b0383161115610e625760405162461bcd60e51b8152600401610607906154a1565b620f4240811015610e855760405162461bcd60e51b81526004016106079061551e565b6040518060e001604052806001151581526020016001151581526020014264ffffffffff168152602001836001600160601b03168152602001836001600160601b031681526020018560ff1681526020018281525060096000856001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160000160076101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160000160136101000a8154816001600160601b0302191690836001600160601b0316021790555060a082015181600001601f6101000a81548160ff021916908360ff16021790555060c082015181600101559050506008839080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b0316021790555061104c85836001600160601b0316613acf565b9450611059838a83613afb565b505050600101610d8c565b50680168d28e3f0028000081111561108e5760405162461bcd60e51b8152600401610607906154c9565b600a8190556006805460ff60a01b1916600160a01b1790556040517f40fc85fbff9305015298ba6fcee88b7e442a64cc803ddb889327680bbd62270a906110d790600190615343565b60405180910390a16110f168056bc75e2d63100000613b26565b6111048568056bc75e2d631000006137b2565b5050600680546001600160a01b039384166001600160a01b031991821617909155600c805492909316911617905550505050505050565b6001600160a01b03811660009081526009602052604090205460ff165b919050565b60055461010090046001600160a01b031690565b601290565b60055461010090046001600160a01b031633146111a55760405162461bcd60e51b815260040161060790615381565b64e8d4a5100081108015906111c2575067016345785d8a00008111155b6111de5760405162461bcd60e51b81526004016106079061595b565b60078190556040517fccfe595973efc7c1f6c29e31974d380470b9431d7770290185b7129419c7e63e90611213908390615a6c565b60405180910390a150565b60055460009060ff16156112445760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055611259614cc0565b611262856132ca565b9050600061128b8260c0015183606001516001600160601b0316600254600a5489600754613b2f565b9050838110156112ad5760405162461bcd60e51b8152600401610607906154f7565b6112c78260c001516003670de0b6b3a76400008161064a57fe5b8111156112e65760405162461bcd60e51b815260040161060790615672565b6112f18633836134e2565b6112ff8260c00151826135d1565b6001600160a01b038716600090815260096020526040902060010155611325828761360a565b6000611338866611c37937e0800061339f565b9050866001600160a01b0316336001600160a01b03167fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed8460405161137d9190615a6c565b60405180910390a361138f338761379c565b61079361078e87836135d1565b60055461010090046001600160a01b031633146113cb5760405162461bcd60e51b815260040161060790615381565b6006805460ff60a01b1916600160a01b831515021790556040517f40fc85fbff9305015298ba6fcee88b7e442a64cc803ddb889327680bbd62270a90611213908390615343565b60055460009060ff16156114385760405162461bcd60e51b81526004016106079061564d565b611440614cc0565b506001600160a01b038216600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526114ec5760405162461bcd60e51b81526004016106079061569d565b80602001516115155750506001600160a01b0381166000908152600b6020526040902054611158565b60c0015192915050565b60055460ff16156115425760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff166115785760405162461bcd60e51b8152600401610607906156ef565b6000611582610a9a565b905060006115908583613bfe565b9050806115af5760405162461bcd60e51b815260040161060790615478565b60085483146115d05760405162461bcd60e51b8152600401610607906157c5565b60005b838110156116f3576000600882815481106115ea57fe5b6000918252602090912001546001600160a01b03169050611609614cc0565b6000611614836137bc565b915091506000611628868460c0015161339f565b9050806116475760405162461bcd60e51b815260040161060790615478565b88888681811061165357fe5b905060200201358111156116795760405162461bcd60e51b8152600401610607906155f7565b61168d84846116888585613acf565b613c92565b836001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a836040516116d09190615a6c565b60405180910390a36116e3843383613afb565b5050600190920191506115d39050565b506116fd85613b26565b61170733866137b2565b50506005805460ff19169055505050565b60055460ff161561173b5760405162461bcd60e51b81526004016106079061564d565b60058054600160ff19909116179081905561010090046001600160a01b031633146117785760405162461bcd60e51b815260040161060790615381565b8083146117975760405162461bcd60e51b8152600401610607906157c5565b60005b83811015611707576117ec8585838181106117b157fe5b90506020020160208101906117c69190614e28565b8484848181106117d257fe5b90506020020160208101906117e79190615262565b613e72565b60010161179a565b60055460009060ff161561181a5760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff166118505760405162461bcd60e51b8152600401610607906156ef565b611858614cc0565b6000611863866137bc565b9150915084600014156118885760405162461bcd60e51b8152600401610607906159dc565b6118a88260c001516002670de0b6b3a7640000816118a257fe5b0461339f565b8511156118c75760405162461bcd60e51b815260040161060790615423565b60006118ee8360c0015184606001516001600160601b0316600254600a548a600754613f8f565b9050848110156119105760405162461bcd60e51b8152600401610607906154f7565b61191f8784611688858a613acf565b866001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a886040516119629190615a6c565b60405180910390a361197381613b26565b61197d33826137b2565b611988873388613afb565b6005805460ff191690559695505050505050565b6119a4614cc0565b60055460ff16156119c75760405162461bcd60e51b81526004016106079061564d565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526111585760405162461bcd60e51b81526004016106079061569d565b3360009081526001602090815260408083206001600160a01b038616845290915281205480831115611ac8573360009081526001602090815260408083206001600160a01b0388168452909152812055611af7565b611ad281846135d1565b3360009081526001602090815260408083206001600160a01b03891684529091529020555b3360008181526001602090815260408083206001600160a01b038916808552925291829020549151909291600080516020615b3283398151915291610cb99190615a6c565b60055460009060ff1615611b625760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff16611b985760405162461bcd60e51b8152600401610607906156ef565b611ba0614cc0565b6000611bab866137bc565b915091506000611bd68360c0015184606001516001600160601b0316600254600a548a60075461402b565b905080611bf55760405162461bcd60e51b815260040161060790615478565b84811115611c155760405162461bcd60e51b8152600401610607906155f7565b611c2f8360c001516002670de0b6b3a7640000816118a257fe5b811115611c4e5760405162461bcd60e51b815260040161060790615423565b611c5d87846116888585613acf565b866001600160a01b0316336001600160a01b03167f63982df10efd8dfaaaa0fcc7f50b2d93b7cba26ccc48adee2873220d485dc39a83604051611ca09190615a6c565b60405180910390a3611cb186613b26565b611cbb33876137b2565b611988873383613afb565b6001600160a01b031660009081526020819052604090205490565b600554600090819060ff1615611d095760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff16611d3f5760405162461bcd60e51b8152600401610607906156ef565b611d47614cc0565b6000611d52896137bc565b91509150611d5e614cc0565b611d67886132ca565b9050611d838160c001516003670de0b6b3a76400008161064a57fe5b871115611da25760405162461bcd60e51b815260040161060790615672565b6000611dd58460c0015185606001516001600160601b03168460c0015185606001516001600160601b031660075461390a565b905086811115611df75760405162461bcd60e51b815260040161060790615717565b6000611e2b8560c0015186606001516001600160601b03168560c0015186606001516001600160601b03168d6007546140c5565b90508a811115611e4d5760405162461bcd60e51b8152600401610607906155f7565b611e588c3383613afb565b611e638a338b6134e2565b611e6d8482613acf565b9350611e7a8c8686613c92565b846020015115611e8c5760c085018490525b611e9a8360c001518a6135d1565b60c084018190526001600160a01b038b16600090815260096020526040902060010155611ec7838b61360a565b6000611efa8660c0015187606001516001600160601b03168660c0015187606001516001600160601b031660075461390a565b905082811015611f1c5760405162461bcd60e51b815260040161060790615478565b88811115611f3c5760405162461bcd60e51b81526004016106079061580d565b611f46828b613bfe565b831115611f655760405162461bcd60e51b815260040161060790615478565b8a6001600160a01b03168d6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d43378858e604051611fb4929190615a75565b60405180910390a46005805460ff19169055909c909b509950505050505050505050565b600181565b600554600090819060ff16156120055760405162461bcd60e51b81526004016106079061564d565b6005805460ff19166001179055600654600160a01b900460ff1661203b5760405162461bcd60e51b8152600401610607906156ef565b612043614cc0565b600061204e896137bc565b9150915061205a614cc0565b612063886132ca565b905061207f8360c001516002670de0b6b3a7640000816118a257fe5b89111561209e5760405162461bcd60e51b815260040161060790615423565b60006120d18460c0015185606001516001600160601b03168460c0015185606001516001600160601b031660075461390a565b9050868111156120f35760405162461bcd60e51b815260040161060790615717565b60006121278560c0015186606001516001600160601b03168560c0015186606001516001600160601b03168f600754614148565b9050888110156121495760405162461bcd60e51b8152600401610607906154f7565b6121548c338d613afb565b61215f8a33836134e2565b612169848c613acf565b93506121768c8686613c92565b8460200151156121885760c085018490525b6121968360c00151826135d1565b60c084018190526001600160a01b038b166000908152600960205260409020600101556121c3838b61360a565b60006121f68660c0015187606001516001600160601b03168660c0015187606001516001600160601b031660075461390a565b9050828110156122185760405162461bcd60e51b81526004016106079061544d565b888111156122385760405162461bcd60e51b81526004016106079061580d565b6122428c83613bfe565b8311156122615760405162461bcd60e51b815260040161060790615478565b8a6001600160a01b03168d6001600160a01b0316336001600160a01b03167f908fb5ee8f16c6bc9bc3690973819f32a4d4b10188134543c88706e0e1d433788f86604051611fb4929190615a75565b600c546001600160a01b031690565b60055460ff16156122e25760405162461bcd60e51b81526004016106079061564d565b6005805460ff191660011790556001600160a01b03811660008181526009602052604080822090516370a0823160e01b81529092906370a082319061232b9030906004016152a5565b60206040518083038186803b15801561234357600080fd5b505afa158015612357573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237b9190615200565b825490915060ff16156124fa578154610100900460ff166124d7576001600160a01b0383166000908152600b60205260409020548082106124d5576001600160a01b0384166000818152600b6020526040808220829055855461ff001916610100178655517ff7bb8e57ffdfd9a31e7580ee84f68757f44fb4a8a913f44520d22f2da1c955e59190a2600061241083836135d1565b9050600061241e8284613bfe565b9050600061243d6703782dace9d90000612438818561339f565b613acf565b8654600160381b600160981b031916600160381b6001600160601b0383169081029190911766ffffffffff00001916620100004264ffffffffff1602178855600a5491925061248c9190613acf565b600a5585546040516001600160a01b03891691600080516020615b12833981519152916124c991600160381b90046001600160601b031690615a91565b60405180910390a25050505b505b6001600160a01b0383166000908152600960205260409020600101819055612577565b6006546125129084906001600160a01b0316836134e2565b6006546040516360b8257960e11b81526001600160a01b039091169063c1704af29061254490869085906004016152dd565b600060405180830381600087803b15801561255e57600080fd5b505af1158015612572573d6000803e3d6000fd5b505050505b50506005805460ff1916905550565b60055460009060ff16156125ac5760405162461bcd60e51b81526004016106079061564d565b6125b4614cc0565b506001600160a01b038216600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c08301526126605760405162461bcd60e51b81526004016106079061569d565b8060200151156126825760405162461bcd60e51b8152600401610607906157ea565b50506001600160a01b03166000908152600b602052604090205490565b60055460009060ff16156126c55760405162461bcd60e51b81526004016106079061564d565b50600a5490565b60055460009060ff16156126f25760405162461bcd60e51b81526004016106079061564d565b6001600160a01b03821660009081526009602052604090205460ff1661272a5760405162461bcd60e51b81526004016106079061569d565b506001600160a01b0316600090815260096020526040902054600160381b90046001600160601b031690565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109b05780601f10610985576101008083540402835291602001916109b0565b600554600090819060ff16156127df5760405162461bcd60e51b81526004016106079061564d565b6008546000908190815b8181101561289057600881815481106127fe57fe5b60009182526020808320909101546001600160a01b03168083526009909152604090912080549195509060ff61010090910416801561284d57508054600160981b90046001600160601b031615155b15612887576001810154600a54825461287f929161287a91600160381b90046001600160601b0316613bfe565b61339f565b935050612890565b506001016127e9565b50600082116128b15760405162461bcd60e51b8152600401610607906153ad565b5090925090509091565b60055461010090046001600160a01b031633146128ea5760405162461bcd60e51b815260040161060790615381565b6001600160a01b0382166000908152600960205260409020805460ff166129235760405162461bcd60e51b81526004016106079061569d565b8054610100900460ff161561294a5760405162461bcd60e51b8152600401610607906157ea565b6001600160a01b0383166000908152600b602052604090819020839055517e0c7a55677231b335e6dea005fa240ac2aeafbd62f188372a7d66892b722c529061299690859085906152dd565b60405180910390a1505050565b60006129b03384846139e6565b50600192915050565b60055460ff16156129dc5760405162461bcd60e51b81526004016106079061564d565b6005805460ff191660011790556008548114612a0a5760405162461bcd60e51b8152600401610607906157c5565b6000612a14610a9a565b90506000612a29856611c37937e0800061339f565b90506000612a3786836135d1565b90506000612a458285613bfe565b905080612a645760405162461bcd60e51b815260040161060790615478565b612a6e338861379c565b600c54612a84906001600160a01b0316846137b2565b612a8d826137a6565b60005b85811015612c7057600060088281548110612aa757fe5b6000918252602090912001546001600160a01b03169050612ac6614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158352610100820481161580159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c0830152612c34576000612b6a858360c0015161339f565b905080612b895760405162461bcd60e51b815260040161060790615478565b898985818110612b9557fe5b90506020020135811015612bbb5760405162461bcd60e51b8152600401610607906154f7565b612bc98260c00151826135d1565b6001600160a01b0384166000818152600960205260409081902060010192909255905133907fe74c91552b64c2e2e7bd255639e004e693bd3e1d01cc33e65610b86afcc1ffed90612c1b908590615a6c565b60405180910390a3612c2e8333836134e2565b50612c66565b888884818110612c4057fe5b90506020020135600014612c665760405162461bcd60e51b8152600401610607906156c4565b5050600101612a90565b50506005805460ff19169055505050505050565b60055460ff1615612ca75760405162461bcd60e51b81526004016106079061564d565b60058054600160ff19909116179081905561010090046001600160a01b03163314612ce45760405162461bcd60e51b815260040161060790615381565b8285148015612cf257508085145b612d0e5760405162461bcd60e51b8152600401610607906157c5565b60085460608167ffffffffffffffff81118015612d2a57600080fd5b50604051908082528060200260200182016040528015612d54578160200160208202803683370190505b50905060608767ffffffffffffffff81118015612d7057600080fd5b50604051908082528060200260200182016040528015612daa57816020015b612d97614cc0565b815260200190600190039081612d8f5790505b50905060005b88811015612ee557600960008b8b84818110612dc857fe5b9050602002016020810190612ddd9190614e28565b6001600160a01b031681526020808201929092526040908101600020815160e081018352815460ff808216151583526101008204811615159583019590955264ffffffffff62010000820416938201939093526001600160601b03600160381b840481166060830152600160981b8404166080820152600160f81b90920490921660a082015260019091015460c08201528251839083908110612e7c57fe5b6020026020010181905250818181518110612e9357fe5b60200260200101516000015115612edd57600183838381518110612eb357fe5b602002602001015160a0015160ff1681518110612ecc57fe5b911515602092830291909101909101525b600101612db0565b5060005b83811015612f3b57828181518110612efd57fe5b6020026020010151612f3357612f3360088281548110612f1957fe5b60009182526020822001546001600160a01b031690613e72565b600101612ee9565b5060005b888110156130075760008a8a83818110612f5557fe5b9050602002016020810190612f6a9190614e28565b90506000898984818110612f7a57fe5b9050602002016020810190612f8f9190615262565b90506703782dace9d900006001600160601b0382161015612fb557506703782dace9d900005b838381518110612fc157fe5b602002602001015160000151612ff357612fee82898986818110612fe157fe5b90506020020135836141c9565b612ffd565b612ffd8282613e72565b5050600101612f3f565b50506005805460ff191690555050505050505050565b60055460609060ff16156130435760405162461bcd60e51b81526004016106079061564d565b60088054806020026020016040519081016040528092919081815260200182805480156109b057602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161307b575050505050905090565b60085490565b60055460009060ff16156130ce5760405162461bcd60e51b81526004016106079061564d565b5060075490565b3360009081526001602090815260408083206001600160a01b03861684529091528120546131039083613acf565b3360008181526001602090815260408083206001600160a01b03891680855292529182902084905590519092600080516020615b3283398151915291610a019190615a6c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60055460009060ff161561319a5760405162461bcd60e51b81526004016106079061564d565b6001600160a01b0382166000908152600960205260409020805460ff166131d35760405162461bcd60e51b81526004016106079061569d565b6001015492915050565b60055461010090046001600160a01b0316331461320c5760405162461bcd60e51b815260040161060790615381565b6040516317066a5760e21b81526001600160a01b03831690635c19a95c906132389084906004016152a5565b600060405180830381600087803b15801561325257600080fd5b505af1158015613266573d6000803e3d6000fd5b505050505050565b600c546001600160a01b031633146132985760405162461bcd60e51b81526004016106079061576c565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600654600160a01b900460ff1690565b6132d2614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff80821615158084526101008304821615159584019590955264ffffffffff62010000830416958301959095526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490931660a08401526001015460c083015261337e5760405162461bcd60e51b81526004016106079061569d565b80602001516111585760405162461bcd60e51b8152600401610607906156c4565b60008282028315806133b95750828482816133b657fe5b04145b6133d55760405162461bcd60e51b81526004016106079061579b565b6706f05b59d3b200008101818110156134005760405162461bcd60e51b81526004016106079061579b565b6000670de0b6b3a7640000825b049695505050505050565b6000806134258786613bfe565b9050600061343b670de0b6b3a7640000836135d1565b90506000613449828661339f565b9050600061346887613463670de0b6b3a7640000856135d1565b613bfe565b905060006134768c836135d1565b90506000613484828e613bfe565b9050600061349282886144a9565b905060006134a0828e61339f565b905060006134ae8e836135d1565b90506134cd81613463670de0b6b3a76400006611c37937e080006135d1565b99505050505050505050509695505050505050565b60006060846001600160a01b031663a9059cbb60e01b858560405160240161350b9291906152dd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516135499190615289565b6000604051808303816000865af19150503d8060008114613586576040519150601f19603f3d011682016040523d82523d6000602084013e61358b565b606091505b50915091508180156135b55750805115806135b55750808060200190518101906135b591906151cc565b610b945760405162461bcd60e51b8152600401610607906158b3565b60008060006135e0858561455c565b9150915080156136025760405162461bcd60e51b8152600401610607906158dc565b509392505050565b81608001516001600160601b031682606001516001600160601b031611158061363557508160200151155b8061364e5750610e10826040015164ffffffffff164203105b1561365857613798565b6060820151608083015160006136816001600160601b0384166064670de0b6b3a76400006118a2565b905060006136a1846001600160601b0316846001600160601b03166135d1565b9050818111156136c4576136be846001600160601b0316836135d1565b92508190505b6703782dace9d900006001600160601b038416116136fe57600a54600093506136ed90846135d1565b600a556136f985614581565b613266565b61370a600a54826135d1565b600a556001600160601b038316606087018190526001600160a01b038616600081815260096020526040908190208054600160381b600160981b031916600160381b9094029390931766ffffffffff00001916620100004264ffffffffff1602179092559051600080516020615b128339815191529061378b908690615a91565b60405180910390a2505050505b5050565b61379882826148c3565b6137af816148ce565b50565b6137988282614977565b6137c4614cc0565b506001600160a01b0381166000908152600960209081526040808320815160e081018352815460ff80821615158084526101008304821615159684019690965264ffffffffff62010000830416948301949094526001600160601b03600160381b820481166060840152600160981b8204166080830152600160f81b900490921660a08301526001015460c082015291906138715760405162461bcd60e51b81526004016106079061569d565b5060c08101516020820151613905576001600160a01b0383166000908152600b602052604081205460c084018190526138b8906138ae90846135d1565b8460c00151613bfe565b905060006138dc600a6004670de0b6b3a76400005b04816138d557fe5b048361339f565b90506138f46004670de0b6b3a76400005b0482613acf565b6001600160601b0316606085015250505b915091565b6000806139178787613bfe565b905060006139258686613bfe565b905060006139338383613bfe565b90506000613955670de0b6b3a7640000613463670de0b6b3a7640000896135d1565b9050613961828261339f565b9a9950505050505050505050565b600354600260001961010060018416150201909116041580156139925750815115155b801561399e5750805115155b6139ba5760405162461bcd60e51b81526004016106079061561d565b81516139cd906003906020850190614cfc565b5080516139e1906004906020840190614cfc565b505050565b6001600160a01b038316600090815260208190526040902054811115613a1e5760405162461bcd60e51b815260040161060790615547565b6001600160a01b038316600090815260208190526040902054613a4190826135d1565b6001600160a01b038085166000908152602081905260408082209390935590841681522054613a709082613acf565b6001600160a01b0380841660008181526020819052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613ac2908590615a6c565b60405180910390a3505050565b600082820183811015613af45760405162461bcd60e51b815260040161060790615907565b9392505050565b60006060846001600160a01b03166323b872dd60e01b85308660405160240161350b939291906152b9565b6137af81614982565b600080613b3c8786613bfe565b90506000613b5d8561287a670de0b6b3a76400006611c37937e080006135d1565b90506000613b6b88836135d1565b90506000613b79828a613bfe565b90506000613b9882613b93670de0b6b3a764000088613bfe565b6144a9565b90506000613ba6828e61339f565b90506000613bb48e836135d1565b90506000613bd3613bcd670de0b6b3a76400008a6135d1565b8b61339f565b9050613beb8261287a670de0b6b3a7640000846135d1565b9f9e505050505050505050505050505050565b600081613c1d5760405162461bcd60e51b81526004016106079061585e565b670de0b6b3a76400008302831580613c455750670de0b6b3a7640000848281613c4257fe5b04145b613c615760405162461bcd60e51b81526004016106079061559e565b60028304810181811015613c875760405162461bcd60e51b81526004016106079061559e565b600084828161340d57fe5b8160200151613e45578160c001518110613dee576001600160a01b0383166000818152600b6020908152604080832083905560098252808320805461ff001916610100179055600191860191909152517ff7bb8e57ffdfd9a31e7580ee84f68757f44fb4a8a913f44520d22f2da1c955e59190a26000613d16828460c001516135d1565b90506000613d28828560c00151613bfe565b9050613d406703782dace9d90000612438818461339f565b6001600160601b03908116606086018181526001600160a01b03881660009081526009602052604090208054600160381b600160981b031916600160381b9093029290921766ffffffffff00001916620100004264ffffffffff160217909155600a549051613daf9216613acf565b600a5560608401516040516001600160a01b03871691600080516020615b1283398151915291613ddf9190615a91565b60405180910390a25050613e40565b6000613e016138ae8460c00151846135d1565b90506000613e1a600a6004670de0b6b3a76400006138cd565b9050613e2f6004670de0b6b3a76400006138ed565b6001600160601b0316606085015250505b613e4f565b613e4f82846149f1565b6001600160a01b0390921660009081526009602052604090206001019190915550565b6001600160a01b0382166000908152600960205260409020805460ff16613eab5760405162461bcd60e51b81526004016106079061569d565b6703782dace9d900006001600160601b038316101580613ed257506001600160601b038216155b613eee5760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b0383161115613f205760405162461bcd60e51b8152600401610607906154a1565b80546bffffffffffffffffffffffff60981b1916600160981b6001600160601b038416021781556040516001600160a01b038416907fc7ea88f3376e27ce6ebc2025310023327f743a8377d438258c36b166dd8b298390613f82908590615a91565b60405180910390a2505050565b600080613f9c8786613bfe565b90506000613fbb613fb5670de0b6b3a7640000846135d1565b8561339f565b90506000613fd58661287a670de0b6b3a7640000856135d1565b90506000613fe38b83613acf565b90506000613ff1828d613bfe565b90506000613fff82876144a9565b9050600061400d828d61339f565b9050614019818d6135d1565b9e9d5050505050505050505050505050565b6000806140388786613bfe565b905060006140468786613acf565b905060006140548289613bfe565b9050600061406a670de0b6b3a764000085613bfe565b9050600061407883836144a9565b90506000614086828e61339f565b90506000614094828f6135d1565b905060006140ad613bcd670de0b6b3a76400008a6135d1565b9050613beb82613463670de0b6b3a7640000846135d1565b6000806140d28588613bfe565b905060006140e087866135d1565b905060006140ee8883613bfe565b905060006140fc82856144a9565b905061411081670de0b6b3a76400006135d1565b9050614124670de0b6b3a7640000876135d1565b94506141396141338c8361339f565b86613bfe565b9b9a5050505050505050505050565b6000806141558786613bfe565b9050600061416b670de0b6b3a7640000856135d1565b9050614177858261339f565b905060006141898a6134638c85613acf565b9050600061419782856144a9565b905060006141ad670de0b6b3a7640000836135d1565b90506141b98a8261339f565b9c9b505050505050505050505050565b6001600160a01b03831660009081526009602052604090205460ff16156142025760405162461bcd60e51b8152600401610607906153d5565b6703782dace9d900006001600160601b03821610156142335760405162461bcd60e51b815260040161060790615744565b68015af1d78b58c400006001600160601b03821611156142655760405162461bcd60e51b8152600401610607906154a1565b620f42408210156142885760405162461bcd60e51b81526004016106079061551e565b6040518060e00160405280600115158152602001600015158152602001600064ffffffffff16815260200160006001600160601b03168152602001826001600160601b0316815260200160088054905060ff168152602001600081525060096000856001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548164ffffffffff021916908364ffffffffff16021790555060608201518160000160076101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160000160136101000a8154816001600160601b0302191690836001600160601b0316021790555060a082015181600001601f6101000a81548160ff021916908360ff16021790555060c082015181600101559050506008839080600181540180825580915050600190039060005260206000200160009091909190916101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600b6000856001600160a01b03166001600160a01b0316815260200190815260200160002081905550826001600160a01b03167fb2daf560899f6307b318aecfb57eb2812c488da4a4c1cad2019b482fa63294ed8284604051613f82929190615aa5565b600060018310156144cc5760405162461bcd60e51b815260040161060790615884565b671bc16d674ec7ffff8311156144f45760405162461bcd60e51b8152600401610607906159ac565b60006144ff83614b62565b9050600061450d84836135d1565b905060006145238661451e85614b7d565b614b8b565b905081614534579250610a0d915050565b600061454587846305f5e100614be2565b9050614551828261339f565b979650505050505050565b600080828410614572575050808203600061457a565b505081810360015b9250929050565b614589614cc0565b506001600160a01b038116600090815260096020908152604091829020825160e081018452815460ff808216151583526101008204811615159483019490945264ffffffffff62010000820416948201949094526001600160601b03600160381b850481166060830152600160981b8504166080820152600160f81b90930490911660a0830181905260019091015460c08301819052600854909190600019018082146146e7576008818154811061463d57fe5b600091825260209091200154600880546001600160a01b03909216918490811061466357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160096000600885815481106146a357fe5b60009182526020808320909101546001600160a01b031683528201929092526040019020805460ff92909216600160f81b026001600160f81b039092169190911790555b60088054806146f257fe5b60008281526020808220600019908401810180546001600160a01b03191690559092019092556040805160e081018252838152808301848152818301858152606083018681526080840187815260a0850188815260c086018981526001600160a01b038f81168b52600990995296909820945185549451935192519151985160ff199095169015151761ff001916610100931515939093029290921766ffffffffff000019166201000064ffffffffff9092169190910217600160381b600160981b031916600160381b6001600160601b0392831602176bffffffffffffffffffffffff60981b1916600160981b9190961602949094176001600160f81b0316600160f81b60ff90951694909402939093178355516001929092019190915560065461482191879116856134e2565b6006546040516360b8257960e11b81526001600160a01b039091169063c1704af29061485390889087906004016152dd565b600060405180830381600087803b15801561486d57600080fd5b505af1158015614881573d6000803e3d6000fd5b505050507f12a8262eb28ee8a8c11e6cf411b3af6ce5bea42abb36e051bf0a65ae602d52ec856040516148b491906152a5565b60405180910390a15050505050565b6137988230836139e6565b306000908152602081905260409020548111156148fd5760405162461bcd60e51b815260040161060790615547565b3060009081526020819052604090205461491790826135d1565b3060009081526020819052604090205560025461493490826135d1565b60025560405160009030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061496c908590615a6c565b60405180910390a350565b6137983083836139e6565b3060009081526020819052604090205461499c9082613acf565b306000908152602081905260409020556002546149b99082613acf565b60025560405130906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061496c908590615a6c565b81608001516001600160601b031682606001516001600160601b0316101580614a1c57508160200151155b80614a355750610e10826040015164ffffffffff164203105b15614a3f57613798565b606082015160808301516000614a686001600160601b0384166064670de0b6b3a76400006118a2565b90506000614a88836001600160601b0316856001600160601b03166135d1565b905081811115614aab57614aa5846001600160601b031683613acf565b92508190505b614ab7600a5482613acf565b600a819055680168d28e3f002800001015614ae45760405162461bcd60e51b8152600401610607906154c9565b6001600160601b038316606087018190526001600160a01b038616600081815260096020526040908190208054600160381b600160981b031916600160381b9094029390931766ffffffffff00001916620100004264ffffffffff1602179092559051600080516020615b128339815191529061378b908690615a91565b6000670de0b6b3a7640000614b7683614b7d565b0292915050565b670de0b6b3a7640000900490565b60008060028306614ba457670de0b6b3a7640000614ba6565b835b90506002830492505b8215613af457614bbf848561339f565b93506002830615614bd757614bd4818561339f565b90505b600283049250614baf565b6000828180614bf987670de0b6b3a764000061455c565b9092509050670de0b6b3a764000080600060015b888410614cb1576000670de0b6b3a764000082029050600080614c418a614c3c85670de0b6b3a76400006135d1565b61455c565b91509150614c538761287a848c61339f565b9650614c5f8784613bfe565b965086614c6e57505050614cb1565b8715614c78579315935b8015614c82579315935b8415614c9957614c9286886135d1565b9550614ca6565b614ca38688613acf565b95505b505050600101614c0d565b50909998505050505050505050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614d3d57805160ff1916838001178555614d6a565b82800160010185558215614d6a579182015b82811115614d6a578251825591602001919060010190614d4f565b50614d76929150614d7a565b5090565b5b80821115614d765760008155600101614d7b565b80356001600160a01b0381168114610a0d57600080fd5b60008083601f840112614db7578182fd5b50813567ffffffffffffffff811115614dce578182fd5b602083019150836020808302850101111561457a57600080fd5b60008083601f840112614df9578182fd5b50813567ffffffffffffffff811115614e10578182fd5b60208301915083602082850101111561457a57600080fd5b600060208284031215614e39578081fd5b613af48383614d8f565b60008060408385031215614e55578081fd5b614e5f8484614d8f565b9150614e6e8460208501614d8f565b90509250929050565b600080600060608486031215614e8b578081fd5b8335614e9681615aee565b92506020840135614ea681615aee565b929592945050506040919091013590565b600080600080600060608688031215614ece578081fd5b8535614ed981615aee565b9450602086013567ffffffffffffffff80821115614ef5578283fd5b614f0189838a01614de8565b90965094506040880135915080821115614f19578283fd5b50614f2688828901614de8565b969995985093965092949392505050565b60008060408385031215614f49578182fd5b614f538484614d8f565b946020939093013593505050565b600080600080600060a08688031215614f78578081fd5b614f828787614d8f565b945060208601359350614f988760408801614d8f565b94979396509394606081013594506080013592915050565b600080600060608486031215614fc4578283fd5b614fce8585614d8f565b95602085013595506040909401359392505050565b600080600080600080600080600060c08a8c031215615000578384fd5b893567ffffffffffffffff80821115615017578586fd5b6150238d838e01614da6565b909b50995060208c013591508082111561503b578586fd5b6150478d838e01614da6565b909950975060408c013591508082111561505f578586fd5b5061506c8c828d01614da6565b90965094505060608a013561508081615aee565b925060808a013561509081615aee565b915060a08a01356150a081615aee565b809150509295985092959850929598565b600080600080604085870312156150c6578384fd5b843567ffffffffffffffff808211156150dd578586fd5b6150e988838901614da6565b90965094506020870135915080821115615101578384fd5b5061510e87828801614da6565b95989497509550505050565b60008060008060008060608789031215615132578384fd5b863567ffffffffffffffff80821115615149578586fd5b6151558a838b01614da6565b9098509650602089013591508082111561516d578586fd5b6151798a838b01614da6565b90965094506040890135915080821115615191578384fd5b5061519e89828a01614da6565b979a9699509497509295939492505050565b6000602082840312156151c1578081fd5b8135613af481615b03565b6000602082840312156151dd578081fd5b8151613af481615b03565b6000602082840312156151f9578081fd5b5035919050565b600060208284031215615211578081fd5b5051919050565b60008060006040848603121561522c578081fd5b83359250602084013567ffffffffffffffff811115615249578182fd5b61525586828701614da6565b9497909650939450505050565b600060208284031215615273578081fd5b81356001600160601b0381168114613af4578182fd5b6000825161529b818460208701615abe565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156153375783516001600160a01b031683529284019291840191600101615312565b50909695505050505050565b901515815260200190565b600060208252825180602084015261536d816040850160208701615abe565b601f01601f19169190910160400192915050565b60208082526012908201527122a9292fa727aa2fa1a7a72a2927a62622a960711b604082015260600190565b6020808252600e908201526d4552525f4e4f4e455f524541445960901b604082015260600190565b6020808252600c908201526b11549497d254d7d093d5539160a21b604082015260600190565b6020808252600e908201526d4552525f4d41585f544f4b454e5360901b604082015260600190565b60208082526010908201526f4552525f4d41585f494e5f524154494f60801b604082015260600190565b60208082526011908201527022a9292fa6a0aa242fa0a8282927ac2f9960791b604082015260600190565b6020808252600f908201526e08aa4a4be9a82a890be82a0a0a49eb608b1b604082015260600190565b6020808252600e908201526d11549497d3505617d5d15251d21560921b604082015260600190565b60208082526014908201527311549497d3505617d513d5105317d5d15251d21560621b604082015260600190565b6020808252600d908201526c11549497d31253525517d3d555609a1b604082015260600190565b6020808252600f908201526e4552525f4d494e5f42414c414e434560881b604082015260600190565b60208082526014908201527311549497d25394d551919250d251539517d0905360621b604082015260600190565b6020808252600f908201526e11549497d253925512505312569151608a1b604082015260600190565b60208082526010908201526f11549497d1125597d25395115493905360821b604082015260600190565b60208082526015908201527422a9292fa12a27a5a2a72fa120a22fa1a0a62622a960591b604082015260600190565b6020808252600c908201526b22a9292fa624a6a4aa2fa4a760a11b604082015260600190565b60208082526016908201527511549497d09513d2d15397d25392551250531256915160521b604082015260600190565b6020808252600b908201526a4552525f5245454e54525960a81b604082015260600190565b6020808252601190820152704552525f4d41585f4f55545f524154494f60781b604082015260600190565b6020808252600d908201526c11549497d393d517d093d55391609a1b604082015260600190565b6020808252601190820152704552525f4f55545f4e4f545f524541445960781b604082015260600190565b6020808252600e908201526d4552525f4e4f545f5055424c494360901b604082015260600190565b6020808252601390820152724552525f4241445f4c494d49545f505249434560681b604082015260600190565b6020808252600e908201526d11549497d3525397d5d15251d21560921b604082015260600190565b60208082526015908201527411549497d393d517d1915157d49150d25412515395605a1b604082015260600190565b60208082526010908201526f4552525f4d554c5f4f564552464c4f5760801b604082015260600190565b6020808252600b908201526a22a9292fa0a9292fa622a760a91b604082015260600190565b6020808252600990820152684552525f524541445960b81b604082015260600190565b6020808252600f908201526e4552525f4c494d49545f505249434560881b604082015260600190565b6020808252600e908201526d11549497d0d3d3919251d554915160921b604082015260600190565b6020808252600c908201526b4552525f4449565f5a45524f60a01b604082015260600190565b6020808252601590820152744552525f42504f575f424153455f544f4f5f4c4f5760581b604082015260600190565b6020808252600f908201526e4552525f45524332305f46414c534560881b604082015260600190565b6020808252601190820152704552525f5355425f554e444552464c4f5760781b604082015260600190565b60208082526010908201526f4552525f4144445f4f564552464c4f5760801b604082015260600190565b60208082526010908201526f4552525f4e554c4c5f4144445245535360801b604082015260600190565b6020808252600f908201526e4552525f494e56414c49445f46454560881b604082015260600190565b6020808252600e908201526d4552525f4d494e5f544f4b454e5360901b604082015260600190565b60208082526016908201527508aa4a4be84a09eaebe8482a68abea89e9ebe90928e960531b604082015260600190565b6020808252600b908201526a22a9292fad22a927afa4a760a91b604082015260600190565b600060e08201905082511515825260208301511515602083015264ffffffffff604084015116604083015260608301516001600160601b038082166060850152806080860151166080850152505060ff60a08401511660a083015260c083015160c083015292915050565b90815260200190565b918252602082015260400190565b60ff91909116815260200190565b6001600160601b0391909116815260200190565b6001600160601b03929092168252602082015260400190565b60005b83811015615ad9578181015183820152602001615ac1565b83811115615ae8576000848401525b50505050565b6001600160a01b03811681146137af57600080fd5b80151581146137af57600080fdfe21b12aed5d425f5675450ffeeae01039085e5323974c3099e1828155d9b51e778c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a264697066735822122018b2550a0d179afba2d654006db034e06e0e741847346b333f104cd911ac2cd264736f6c634300060c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.