Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 112 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Transfer Ownersh... | 19126258 | 254 days ago | IN | 0 ETH | 0.00045318 | ||||
Smart Swap Exact... | 18593013 | 328 days ago | IN | 0 ETH | 0.02597697 | ||||
Smart Swap Exact... | 18592319 | 328 days ago | IN | 0 ETH | 0.02531754 | ||||
Smart Swap Exact... | 18588637 | 329 days ago | IN | 0 ETH | 0.04078726 | ||||
Smart Swap Exact... | 18586860 | 329 days ago | IN | 0 ETH | 0.02710513 | ||||
Smart Swap Exact... | 18586623 | 329 days ago | IN | 0 ETH | 0.02927457 | ||||
Smart Swap Exact... | 18584598 | 330 days ago | IN | 0 ETH | 0.02183578 | ||||
Smart Swap Exact... | 18582889 | 330 days ago | IN | 0 ETH | 0.01782206 | ||||
Smart Swap Exact... | 18580988 | 330 days ago | IN | 0 ETH | 0.02168121 | ||||
Smart Swap Exact... | 18575034 | 331 days ago | IN | 0 ETH | 0.01479487 | ||||
Smart Swap Exact... | 18574254 | 331 days ago | IN | 0 ETH | 0.0190441 | ||||
Smart Swap Exact... | 18572688 | 331 days ago | IN | 0 ETH | 0.0274582 | ||||
Smart Swap Exact... | 18572224 | 331 days ago | IN | 0 ETH | 0.02802316 | ||||
Smart Swap Exact... | 18571295 | 331 days ago | IN | 0 ETH | 0.03188786 | ||||
Smart Swap Exact... | 18570093 | 332 days ago | IN | 0 ETH | 0.01740448 | ||||
Smart Swap Exact... | 18561112 | 333 days ago | IN | 0 ETH | 0.01303921 | ||||
Smart Swap Exact... | 18557305 | 333 days ago | IN | 0 ETH | 0.03059474 | ||||
Smart Swap Exact... | 18556833 | 333 days ago | IN | 0 ETH | 0.03075568 | ||||
Smart Swap Exact... | 18556450 | 333 days ago | IN | 0 ETH | 0.01996325 | ||||
Smart Swap Exact... | 18555227 | 334 days ago | IN | 0 ETH | 0.01638606 | ||||
Smart Swap Exact... | 18554389 | 334 days ago | IN | 0 ETH | 0.01393542 | ||||
Smart Swap Exact... | 18554113 | 334 days ago | IN | 0 ETH | 0.01272364 | ||||
Smart Swap Exact... | 18551652 | 334 days ago | IN | 0 ETH | 0.01931985 | ||||
Smart Swap Exact... | 18551488 | 334 days ago | IN | 0 ETH | 0.0219659 | ||||
Smart Swap Exact... | 18551230 | 334 days ago | IN | 0 ETH | 0.02167545 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
BPoolProxy
Compiler Version
v0.7.4+commit.3f05b770
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC1155/ERC1155Holder.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./ISwap.sol"; import "../interfaces/IXToken.sol"; import "../interfaces/IXTokenWrapper.sol"; import "../interfaces/IBPool.sol"; import "../interfaces/IBRegistry.sol"; import "../interfaces/IProtocolFee.sol"; import "../interfaces/IUTokenPriceFeed.sol"; /** * @title BPoolProxy * @author Protofire * @dev Forwarding proxy that allows users to batch execute swaps and join/exit pools. * User should interact with pools through this contracts as it is the one that charge * the protocol swap fee, and wrap/unwrap pool tokens into/from xPoolToken. * * This code is based on Balancer ExchangeProxy contract * https://docs.balancer.finance/smart-contracts/exchange-proxy * (https://etherscan.io/address/0x3E66B66Fd1d0b02fDa6C811Da9E0547970DB2f21#code) */ contract BPoolProxy is Ownable, ISwap, ERC1155Holder { using SafeMath for uint256; struct Pool { address pool; uint256 tokenBalanceIn; uint256 tokenWeightIn; uint256 tokenBalanceOut; uint256 tokenWeightOut; uint256 swapFee; uint256 effectiveLiquidity; } uint256 private constant BONE = 10**18; /// @dev Address of BRegistry IBRegistry public registry; /// @dev Address of ProtocolFee module IProtocolFee public protocolFee; /// @dev Address of XTokenWrapper IXTokenWrapper public xTokenWrapper; /// @dev Address of Utitlity Token Price Feed - Used as feature flag for discounted fee IUTokenPriceFeed public utilityTokenFeed; /// @dev Address who receives fees address public feeReceiver; /// @dev Address Utitlity Token - Used as feature flag for discounted fee address public utilityToken; /** * @dev Emitted when `joinPool` function is executed. */ event JoinPool(address liquidityProvider, address bpool, uint256 shares); /** * @dev Emitted when `exitPool` function is executed. */ event ExitPool(address iquidityProvider, address bpool, uint256 shares); /** * @dev Emitted when `registry` address is set. */ event RegistrySet(address registry); /** * @dev Emitted when `protocolFee` address is set. */ event ProtocolFeeSet(address protocolFee); /** * @dev Emitted when `feeReceiver` address is set. */ event FeeReceiverSet(address feeReceiver); /** * @dev Emitted when `xTokenWrapper` address is set. */ event XTokenWrapperSet(address xTokenWrapper); /** * @dev Emitted when `utilityToken` address is set. */ event UtilityTokenSet(address utilityToken); /** * @dev Emitted when `utilityTokenFeed` address is set. */ event UtilityTokenFeedSet(address utilityTokenFeed); /** * @dev Sets the values for {registry}, {protocolFee}, {feeReceiver}, * {xTokenWrapper}, {utilityToken} and {utilityTokenFeed}. * * Sets ownership to the account that deploys the contract. * */ constructor( address _registry, address _protocolFee, address _feeReceiver, address _xTokenWrapper, address _utilityToken, address _utilityTokenFeed ) { _setRegistry(_registry); _setProtocolFee(_protocolFee); _setFeeReceiver(_feeReceiver); _setXTokenWrapper(_xTokenWrapper); _setUtilityToken(_utilityToken); _setUtilityTokenFeed(_utilityTokenFeed); } /** * @dev Sets `_registry` as the new registry. * * Requirements: * * - the caller must be the owner. * - `_registry` should not be the zero address. * * @param _registry The address of the registry. */ function setRegistry(address _registry) external onlyOwner { _setRegistry(_registry); } /** * @dev Sets `_protocolFee` as the new protocolFee. * * Requirements: * * - the caller must be the owner. * - `_protocolFee` should not be the zero address. * * @param _protocolFee The address of the protocolFee. */ function setProtocolFee(address _protocolFee) external onlyOwner { _setProtocolFee(_protocolFee); } /** * @dev Sets `_feeReceiver` as the new feeReceiver. * * Requirements: * * - the caller must be the owner. * - `_feeReceiver` should not be the zero address. * * @param _feeReceiver The address of the feeReceiver. */ function setFeeReceiver(address _feeReceiver) external onlyOwner { _setFeeReceiver(_feeReceiver); } /** * @dev Sets `_xTokenWrapper` as the new xTokenWrapper. * * Requirements: * * - the caller must be the owner. * - `_xTokenWrapper` should not be the zero address. * * @param _xTokenWrapper The address of the xTokenWrapper. */ function setXTokenWrapper(address _xTokenWrapper) external onlyOwner { _setXTokenWrapper(_xTokenWrapper); } /** * @dev Sets `_utilityToken` as the new utilityToken. * * Requirements: * * - the caller must be the owner. * * @param _utilityToken The address of the utilityToken. */ function setUtilityToken(address _utilityToken) external onlyOwner { _setUtilityToken(_utilityToken); } /** * @dev Sets `_utilityTokenFeed` as the new utilityTokenFeed. * * Requirements: * * - the caller must be the owner. * * @param _utilityTokenFeed The address of the utilityTokenFeed. */ function setUtilityTokenFeed(address _utilityTokenFeed) external onlyOwner { _setUtilityTokenFeed(_utilityTokenFeed); } /** * @dev Sets `_registry` as the new registry. * * Requirements: * * - `_registry` should not be the zero address. * * @param _registry The address of the registry. */ function _setRegistry(address _registry) internal { require(_registry != address(0), "registry is the zero address"); emit RegistrySet(_registry); registry = IBRegistry(_registry); } /** * @dev Sets `_protocolFee` as the new protocolFee. * * Requirements: * * - `_protocolFee` should not be the zero address. * * @param _protocolFee The address of the protocolFee. */ function _setProtocolFee(address _protocolFee) internal { require(_protocolFee != address(0), "protocolFee is the zero address"); emit ProtocolFeeSet(_protocolFee); protocolFee = IProtocolFee(_protocolFee); } /** * @dev Sets `_feeReceiver` as the new feeReceiver. * * Requirements: * * - `_feeReceiver` should not be the zero address. * * @param _feeReceiver The address of the feeReceiver. */ function _setFeeReceiver(address _feeReceiver) internal { require(_feeReceiver != address(0), "feeReceiver is the zero address"); emit FeeReceiverSet(_feeReceiver); feeReceiver = _feeReceiver; } /** * @dev Sets `_xTokenWrapper` as the new xTokenWrapper. * * Requirements: * * - `_xTokenWrapper` should not be the zero address. * * @param _xTokenWrapper The address of the xTokenWrapper. */ function _setXTokenWrapper(address _xTokenWrapper) internal { require(_xTokenWrapper != address(0), "xTokenWrapper is the zero address"); emit XTokenWrapperSet(_xTokenWrapper); xTokenWrapper = IXTokenWrapper(_xTokenWrapper); } /** * @dev Sets `_utilityToken` as the new utilityToken. * * @param _utilityToken The address of the utilityToken. */ function _setUtilityToken(address _utilityToken) internal { emit UtilityTokenSet(_utilityToken); utilityToken = _utilityToken; } /** * @dev Sets `_utilityTokenFeed` as the new utilityTokenFeed. * * Requirements: * * - the caller must be the owner. * * @param _utilityTokenFeed The address of the utilityTokenFeed. */ function _setUtilityTokenFeed(address _utilityTokenFeed) internal { emit UtilityTokenFeedSet(_utilityTokenFeed); utilityTokenFeed = IUTokenPriceFeed(_utilityTokenFeed); } /** * @dev Execute single-hop swaps for swapExactIn trade type. Used for swaps * returned from viewSplit function and legacy off-chain SOR. * * @param swaps Array of single-hop swaps. * @param tokenIn Input token. * @param tokenOut Output token. * @param totalAmountIn Total amount of tokenIn. * @param minTotalAmountOut Minumum amount of tokenOut. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function batchSwapExactIn( Swap[] memory swaps, IXToken tokenIn, IXToken tokenOut, uint256 totalAmountIn, uint256 minTotalAmountOut, bool useUtilityToken ) public returns (uint256 totalAmountOut) { transferFrom(tokenIn, totalAmountIn); for (uint256 i = 0; i < swaps.length; i++) { Swap memory swap = swaps[i]; IXToken swapTokenIn = IXToken(swap.tokenIn); IBPool pool = IBPool(swap.pool); if (swapTokenIn.allowance(address(this), swap.pool) > 0) { swapTokenIn.approve(swap.pool, 0); } swapTokenIn.approve(swap.pool, swap.swapAmount); (uint256 tokenAmountOut, ) = pool.swapExactAmountIn( swap.tokenIn, swap.swapAmount, swap.tokenOut, swap.limitReturnAmount, swap.maxPrice ); totalAmountOut = tokenAmountOut.add(totalAmountOut); } require(totalAmountOut >= minTotalAmountOut, "ERR_LIMIT_OUT"); transferFeeFrom(tokenIn, protocolFee.batchFee(swaps, totalAmountIn), useUtilityToken); transfer(tokenOut, totalAmountOut); transfer(tokenIn, getBalance(tokenIn)); } /** * @dev Execute single-hop swaps for swapExactOut trade type. Used for swaps * returned from viewSplit function and legacy off-chain SOR. * * @param swaps Array of single-hop swaps. * @param tokenIn Input token. * @param tokenOut Output token. * @param maxTotalAmountIn Maximum total amount of tokenIn. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function batchSwapExactOut( Swap[] memory swaps, IXToken tokenIn, IXToken tokenOut, uint256 maxTotalAmountIn, bool useUtilityToken ) public returns (uint256 totalAmountIn) { transferFrom(tokenIn, maxTotalAmountIn); for (uint256 i = 0; i < swaps.length; i++) { Swap memory swap = swaps[i]; IXToken swapTokenIn = IXToken(swap.tokenIn); IBPool pool = IBPool(swap.pool); if (swapTokenIn.allowance(address(this), swap.pool) > 0) { swapTokenIn.approve(swap.pool, 0); } swapTokenIn.approve(swap.pool, swap.limitReturnAmount); (uint256 tokenAmountIn, ) = pool.swapExactAmountOut( swap.tokenIn, swap.limitReturnAmount, swap.tokenOut, swap.swapAmount, swap.maxPrice ); totalAmountIn = tokenAmountIn.add(totalAmountIn); } require(totalAmountIn <= maxTotalAmountIn, "ERR_LIMIT_IN"); transferFeeFrom(tokenIn, protocolFee.batchFee(swaps, totalAmountIn), useUtilityToken); transfer(tokenOut, getBalance(tokenOut)); transfer(tokenIn, getBalance(tokenIn)); } /** * @dev Execute multi-hop swaps returned from off-chain SOR for swapExactIn trade type. * * @param swapSequences multi-hop swaps sequence. * @param tokenIn Input token. * @param tokenOut Output token. * @param totalAmountIn Total amount of tokenIn. * @param minTotalAmountOut Minumum amount of tokenOut. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function multihopBatchSwapExactIn( Swap[][] memory swapSequences, IXToken tokenIn, IXToken tokenOut, uint256 totalAmountIn, uint256 minTotalAmountOut, bool useUtilityToken ) external returns (uint256 totalAmountOut) { transferFrom(tokenIn, totalAmountIn); for (uint256 i = 0; i < swapSequences.length; i++) { uint256 tokenAmountOut; for (uint256 k = 0; k < swapSequences[i].length; k++) { Swap memory swap = swapSequences[i][k]; IXToken swapTokenIn = IXToken(swap.tokenIn); if (k == 1) { // Makes sure that on the second swap the output of the first was used // so there is not intermediate token leftover swap.swapAmount = tokenAmountOut; } IBPool pool = IBPool(swap.pool); if (swapTokenIn.allowance(address(this), swap.pool) > 0) { swapTokenIn.approve(swap.pool, 0); } swapTokenIn.approve(swap.pool, swap.swapAmount); (tokenAmountOut, ) = pool.swapExactAmountIn( swap.tokenIn, swap.swapAmount, swap.tokenOut, swap.limitReturnAmount, swap.maxPrice ); } // This takes the amountOut of the last swap totalAmountOut = tokenAmountOut.add(totalAmountOut); } require(totalAmountOut >= minTotalAmountOut, "ERR_LIMIT_OUT"); transferFeeFrom(tokenIn, protocolFee.multihopBatch(swapSequences, totalAmountIn), useUtilityToken); transfer(tokenOut, totalAmountOut); transfer(tokenIn, getBalance(tokenIn)); } /** * @dev Execute multi-hop swaps returned from off-chain SOR for swapExactOut trade type. * * @param swapSequences multi-hop swaps sequence. * @param tokenIn Input token. * @param tokenOut Output token. * @param maxTotalAmountIn Maximum total amount of tokenIn. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function multihopBatchSwapExactOut( Swap[][] memory swapSequences, IXToken tokenIn, IXToken tokenOut, uint256 maxTotalAmountIn, bool useUtilityToken ) external returns (uint256 totalAmountIn) { transferFrom(tokenIn, maxTotalAmountIn); for (uint256 i = 0; i < swapSequences.length; i++) { uint256 tokenAmountInFirstSwap; // Specific code for a simple swap and a multihop (2 swaps in sequence) if (swapSequences[i].length == 1) { Swap memory swap = swapSequences[i][0]; IXToken swapTokenIn = IXToken(swap.tokenIn); IBPool pool = IBPool(swap.pool); if (swapTokenIn.allowance(address(this), swap.pool) > 0) { swapTokenIn.approve(swap.pool, 0); } swapTokenIn.approve(swap.pool, swap.limitReturnAmount); (tokenAmountInFirstSwap, ) = pool.swapExactAmountOut( swap.tokenIn, swap.limitReturnAmount, swap.tokenOut, swap.swapAmount, swap.maxPrice ); } else { // Consider we are swapping A -> B and B -> C. The goal is to buy a given amount // of token C. But first we need to buy B with A so we can then buy C with B // To get the exact amount of C we then first need to calculate how much B we'll need: uint256 intermediateTokenAmount; // This would be token B as described above Swap memory secondSwap = swapSequences[i][1]; IBPool poolSecondSwap = IBPool(secondSwap.pool); intermediateTokenAmount = poolSecondSwap.calcInGivenOut( poolSecondSwap.getBalance(secondSwap.tokenIn), poolSecondSwap.getDenormalizedWeight(secondSwap.tokenIn), poolSecondSwap.getBalance(secondSwap.tokenOut), poolSecondSwap.getDenormalizedWeight(secondSwap.tokenOut), secondSwap.swapAmount, poolSecondSwap.getSwapFee() ); //// Buy intermediateTokenAmount of token B with A in the first pool Swap memory firstSwap = swapSequences[i][0]; IXToken firstswapTokenIn = IXToken(firstSwap.tokenIn); IBPool poolFirstSwap = IBPool(firstSwap.pool); if (firstswapTokenIn.allowance(address(this), firstSwap.pool) < uint256(-1)) { firstswapTokenIn.approve(firstSwap.pool, uint256(-1)); } (tokenAmountInFirstSwap, ) = poolFirstSwap.swapExactAmountOut( firstSwap.tokenIn, firstSwap.limitReturnAmount, firstSwap.tokenOut, intermediateTokenAmount, // This is the amount of token B we need firstSwap.maxPrice ); //// Buy the final amount of token C desired IXToken secondswapTokenIn = IXToken(secondSwap.tokenIn); if (secondswapTokenIn.allowance(address(this), secondSwap.pool) < uint256(-1)) { secondswapTokenIn.approve(secondSwap.pool, uint256(-1)); } poolSecondSwap.swapExactAmountOut( secondSwap.tokenIn, secondSwap.limitReturnAmount, secondSwap.tokenOut, secondSwap.swapAmount, secondSwap.maxPrice ); } totalAmountIn = tokenAmountInFirstSwap.add(totalAmountIn); } require(totalAmountIn <= maxTotalAmountIn, "ERR_LIMIT_IN"); transferFeeFrom(tokenIn, protocolFee.multihopBatch(swapSequences, totalAmountIn), useUtilityToken); transfer(tokenOut, getBalance(tokenOut)); transfer(tokenIn, getBalance(tokenIn)); } /** * @dev Used for swaps returned from viewSplit function. * * @param tokenIn Input token. * @param tokenOut Output token. * @param totalAmountIn Total amount of tokenIn. * @param minTotalAmountOut Minumum amount of tokenOut. * @param nPools Maximum mumber of pools. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function smartSwapExactIn( IXToken tokenIn, IXToken tokenOut, uint256 totalAmountIn, uint256 minTotalAmountOut, uint256 nPools, bool useUtilityToken ) external returns (uint256 totalAmountOut) { Swap[] memory swaps; uint256 totalOutput; (swaps, totalOutput) = viewSplitExactIn(address(tokenIn), address(tokenOut), totalAmountIn, nPools); require(totalOutput >= minTotalAmountOut, "ERR_LIMIT_OUT"); totalAmountOut = batchSwapExactIn(swaps, tokenIn, tokenOut, totalAmountIn, minTotalAmountOut, useUtilityToken); } /** * @dev Used for swaps returned from viewSplit function. * * @param tokenIn Input token. * @param tokenOut Output token. * @param maxTotalAmountIn Maximum total amount of tokenIn. * @param nPools Maximum mumber of pools. * @param useUtilityToken Flag to determine if the protocol swap fee is paid using UtilityToken or TokenIn. */ function smartSwapExactOut( IXToken tokenIn, IXToken tokenOut, uint256 totalAmountOut, uint256 maxTotalAmountIn, uint256 nPools, bool useUtilityToken ) external returns (uint256 totalAmountIn) { Swap[] memory swaps; uint256 totalInput; (swaps, totalInput) = viewSplitExactOut(address(tokenIn), address(tokenOut), totalAmountOut, nPools); require(totalInput <= maxTotalAmountIn, "ERR_LIMIT_IN"); totalAmountIn = batchSwapExactOut(swaps, tokenIn, tokenOut, maxTotalAmountIn, useUtilityToken); } /** * @dev Join the `pool`, getting `poolAmountOut` pool tokens. This will pull some of each of the currently * trading tokens in the pool, meaning you must have called approve for each token for this pool. These * values are limited by the array of `maxAmountsIn` in the order of the pool tokens. * * @param pool Pool address. * @param poolAmountOut Exact pool amount out. * @param maxAmountsIn Maximum amounts in. */ function joinPool( address pool, uint256 poolAmountOut, uint256[] calldata maxAmountsIn ) external { address[] memory tokens = IBPool(pool).getCurrentTokens(); // pull xTokens for (uint256 i = 0; i < tokens.length; i++) { transferFrom(IXToken(tokens[i]), maxAmountsIn[i]); IXToken(tokens[i]).approve(pool, maxAmountsIn[i]); } IBPool(pool).joinPool(poolAmountOut, maxAmountsIn); // push remaining xTokens for (uint256 i = 0; i < tokens.length; i++) { transfer(IXToken(tokens[i]), getBalance(IXToken(tokens[i]))); } // Wrap balancer liquidity tokens into its representing xToken IBPool(pool).approve(address(xTokenWrapper), poolAmountOut); require(xTokenWrapper.wrap(pool, poolAmountOut), "ERR_WRAP_POOL"); transfer(IXToken(xTokenWrapper.tokenToXToken(pool)), poolAmountOut); emit JoinPool(msg.sender, pool, poolAmountOut); } /** * @dev Exit the pool, paying poolAmountIn pool tokens and getting some of each of the currently trading * tokens in return. These values are limited by the array of minAmountsOut in the order of the pool tokens. * * @param pool Pool address. * @param poolAmountIn Exact pool amount int. * @param minAmountsOut Minumum amounts out. */ function exitPool( address pool, uint256 poolAmountIn, uint256[] calldata minAmountsOut ) external { address wrappedLPT = xTokenWrapper.tokenToXToken(pool); // pull wrapped liquitity tokens transferFrom(IXToken(wrappedLPT), poolAmountIn); // unwrap wrapped liquitity tokens require(xTokenWrapper.unwrap(wrappedLPT, poolAmountIn), "ERR_UNWRAP_POOL"); // LPT do not need to be approved when exit IBPool(pool).exitPool(poolAmountIn, minAmountsOut); // push xTokens address[] memory tokens = IBPool(pool).getCurrentTokens(); for (uint256 i = 0; i < tokens.length; i++) { transfer(IXToken(tokens[i]), getBalance(IXToken(tokens[i]))); } emit ExitPool(msg.sender, pool, poolAmountIn); } /** * @dev Pay `tokenAmountIn` of token `tokenIn` to join the pool, getting `poolAmountOut` of the pool shares. * * @param pool Pool address. * @param tokenIn Input token. * @param tokenAmountIn Exact amount of tokenIn to pay. * @param minPoolAmountOut Minumum amount of pool shares to get. */ function joinswapExternAmountIn( address pool, address tokenIn, uint256 tokenAmountIn, uint256 minPoolAmountOut ) external returns (uint256 poolAmountOut) { // pull xToken transferFrom(IXToken(tokenIn), tokenAmountIn); IXToken(tokenIn).approve(pool, tokenAmountIn); poolAmountOut = IBPool(pool).joinswapExternAmountIn(tokenIn, tokenAmountIn, minPoolAmountOut); // Wrap balancer liquidity tokens into its representing xToken IBPool(pool).approve(address(xTokenWrapper), poolAmountOut); require(xTokenWrapper.wrap(pool, poolAmountOut), "ERR_WRAP_POOL"); transfer(IXToken(xTokenWrapper.tokenToXToken(pool)), poolAmountOut); emit JoinPool(msg.sender, pool, poolAmountOut); } /** * @dev Specify `poolAmountOut` pool shares that you want to get, and a token `tokenIn` to pay with. * This costs `tokenAmountIn` tokens (these went into the pool). * * @param pool Pool address. * @param tokenIn Input token. * @param poolAmountOut Exact amount of pool shares to get. * @param maxAmountIn Minumum amount of tokenIn to pay. */ function joinswapPoolAmountOut( address pool, address tokenIn, uint256 poolAmountOut, uint256 maxAmountIn ) external returns (uint256 tokenAmountIn) { // pull xToken transferFrom(IXToken(tokenIn), maxAmountIn); IXToken(tokenIn).approve(pool, maxAmountIn); tokenAmountIn = IBPool(pool).joinswapPoolAmountOut(tokenIn, poolAmountOut, maxAmountIn); // push remaining xTokens transfer(IXToken(tokenIn), getBalance(IXToken(tokenIn))); // Wrap balancer liquidity tokens into its representing xToken IBPool(pool).approve(address(xTokenWrapper), poolAmountOut); require(xTokenWrapper.wrap(pool, poolAmountOut), "ERR_WRAP_POOL"); transfer(IXToken(xTokenWrapper.tokenToXToken(pool)), poolAmountOut); emit JoinPool(msg.sender, pool, poolAmountOut); } /** * @dev Pay `poolAmountIn` pool shares into the pool, getting `tokenAmountOut` of the given * token `tokenOut` out of the pool. * * @param pool Pool address. * @param tokenOut Input token. * @param poolAmountIn Exact amount of pool shares to pay. * @param minAmountOut Minumum amount of tokenIn to get. */ function exitswapPoolAmountIn( address pool, address tokenOut, uint256 poolAmountIn, uint256 minAmountOut ) external returns (uint256 tokenAmountOut) { address wrappedLPT = xTokenWrapper.tokenToXToken(pool); // pull wrapped liquitity tokens transferFrom(IXToken(wrappedLPT), poolAmountIn); // unwrap wrapped liquitity tokens require(xTokenWrapper.unwrap(wrappedLPT, poolAmountIn), "ERR_UNWRAP_POOL"); // LPT do not need to be approved when exit tokenAmountOut = IBPool(pool).exitswapPoolAmountIn(tokenOut, poolAmountIn, minAmountOut); // push xToken transfer(IXToken(tokenOut), tokenAmountOut); emit ExitPool(msg.sender, pool, poolAmountIn); } /** * @dev Specify tokenAmountOut of token tokenOut that you want to get out of the pool. * This costs poolAmountIn pool shares (these went into the pool). * * @param pool Pool address. * @param tokenOut Input token. * @param tokenAmountOut Exact amount of of tokenIn to get. * @param maxPoolAmountIn Maximum amount of pool shares to pay. */ function exitswapExternAmountOut( address pool, address tokenOut, uint256 tokenAmountOut, uint256 maxPoolAmountIn ) external returns (uint256 poolAmountIn) { address wrappedLPT = xTokenWrapper.tokenToXToken(pool); // pull wrapped liquitity tokens transferFrom(IXToken(wrappedLPT), maxPoolAmountIn); // unwrap wrapped liquitity tokens require(xTokenWrapper.unwrap(wrappedLPT, maxPoolAmountIn), "ERR_UNWRAP_POOL"); // LPT do not need to be approved when exit poolAmountIn = IBPool(pool).exitswapExternAmountOut(tokenOut, tokenAmountOut, maxPoolAmountIn); // push xToken transfer(IXToken(tokenOut), tokenAmountOut); uint256 remainingLPT = maxPoolAmountIn.sub(poolAmountIn); if (remainingLPT > 0) { // Wrap remaining balancer liquidity tokens into its representing xToken IBPool(pool).approve(address(xTokenWrapper), remainingLPT); require(xTokenWrapper.wrap(pool, remainingLPT), "ERR_WRAP_POOL"); transfer(IXToken(wrappedLPT), remainingLPT); } emit ExitPool(msg.sender, pool, poolAmountIn); } /** * @dev View function that calculates most optimal swaps (exactIn swap type) across a max of nPools. * Returns an array of `Swaps` and the total amount out for swap. * * @param tokenIn Input token. * @param tokenOut Output token. * @param swapAmount Amount of tokenIn. * @param nPools Maximum mumber of pools. */ function viewSplitExactIn( address tokenIn, address tokenOut, uint256 swapAmount, uint256 nPools ) public view returns (Swap[] memory swaps, uint256 totalOutput) { address[] memory poolAddresses = registry.getBestPoolsWithLimit(tokenIn, tokenOut, nPools); Pool[] memory pools = new Pool[](poolAddresses.length); uint256 sumEffectiveLiquidity; for (uint256 i = 0; i < poolAddresses.length; i++) { pools[i] = getPoolData(tokenIn, tokenOut, poolAddresses[i]); sumEffectiveLiquidity = sumEffectiveLiquidity.add(pools[i].effectiveLiquidity); } uint256[] memory bestInputAmounts = new uint256[](pools.length); uint256 totalInputAmount; for (uint256 i = 0; i < pools.length; i++) { bestInputAmounts[i] = swapAmount.mul(pools[i].effectiveLiquidity).div(sumEffectiveLiquidity); totalInputAmount = totalInputAmount.add(bestInputAmounts[i]); } if (totalInputAmount < swapAmount) { bestInputAmounts[0] = bestInputAmounts[0].add(swapAmount.sub(totalInputAmount)); } else { bestInputAmounts[0] = bestInputAmounts[0].sub(totalInputAmount.sub(swapAmount)); } swaps = new Swap[](pools.length); for (uint256 i = 0; i < pools.length; i++) { swaps[i] = Swap({ pool: pools[i].pool, tokenIn: tokenIn, tokenOut: tokenOut, swapAmount: bestInputAmounts[i], limitReturnAmount: 0, maxPrice: uint256(-1) }); } totalOutput = calcTotalOutExactIn(bestInputAmounts, pools); return (swaps, totalOutput); } /** * @dev View function that calculates most optimal swaps (exactOut swap type) across a max of nPools. * Returns an array of Swaps and the total amount in for swap. * * @param tokenIn Input token. * @param tokenOut Output token. * @param swapAmount Amount of tokenIn. * @param nPools Maximum mumber of pools. */ function viewSplitExactOut( address tokenIn, address tokenOut, uint256 swapAmount, uint256 nPools ) public view returns (Swap[] memory swaps, uint256 totalInput) { address[] memory poolAddresses = registry.getBestPoolsWithLimit(tokenIn, tokenOut, nPools); Pool[] memory pools = new Pool[](poolAddresses.length); uint256 sumEffectiveLiquidity; for (uint256 i = 0; i < poolAddresses.length; i++) { pools[i] = getPoolData(tokenIn, tokenOut, poolAddresses[i]); sumEffectiveLiquidity = sumEffectiveLiquidity.add(pools[i].effectiveLiquidity); } uint256[] memory bestInputAmounts = new uint256[](pools.length); uint256 totalInputAmount; for (uint256 i = 0; i < pools.length; i++) { bestInputAmounts[i] = swapAmount.mul(pools[i].effectiveLiquidity).div(sumEffectiveLiquidity); totalInputAmount = totalInputAmount.add(bestInputAmounts[i]); } if (totalInputAmount < swapAmount) { bestInputAmounts[0] = bestInputAmounts[0].add(swapAmount.sub(totalInputAmount)); } else { bestInputAmounts[0] = bestInputAmounts[0].sub(totalInputAmount.sub(swapAmount)); } swaps = new Swap[](pools.length); for (uint256 i = 0; i < pools.length; i++) { swaps[i] = Swap({ pool: pools[i].pool, tokenIn: tokenIn, tokenOut: tokenOut, swapAmount: bestInputAmounts[i], limitReturnAmount: uint256(-1), maxPrice: uint256(-1) }); } totalInput = calcTotalOutExactOut(bestInputAmounts, pools); return (swaps, totalInput); } function getPoolData( address tokenIn, address tokenOut, address poolAddress ) internal view returns (Pool memory) { IBPool pool = IBPool(poolAddress); uint256 tokenBalanceIn = pool.getBalance(tokenIn); uint256 tokenBalanceOut = pool.getBalance(tokenOut); uint256 tokenWeightIn = pool.getDenormalizedWeight(tokenIn); uint256 tokenWeightOut = pool.getDenormalizedWeight(tokenOut); uint256 swapFee = pool.getSwapFee(); uint256 effectiveLiquidity = calcEffectiveLiquidity(tokenWeightIn, tokenBalanceOut, tokenWeightOut); Pool memory returnPool = Pool({ pool: poolAddress, tokenBalanceIn: tokenBalanceIn, tokenWeightIn: tokenWeightIn, tokenBalanceOut: tokenBalanceOut, tokenWeightOut: tokenWeightOut, swapFee: swapFee, effectiveLiquidity: effectiveLiquidity }); return returnPool; } function calcEffectiveLiquidity( uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut ) internal pure returns (uint256 effectiveLiquidity) { // Bo * wi/(wi+wo) effectiveLiquidity = tokenWeightIn.mul(BONE).div(tokenWeightOut.add(tokenWeightIn)).mul(tokenBalanceOut).div( BONE ); return effectiveLiquidity; } function calcTotalOutExactIn(uint256[] memory bestInputAmounts, Pool[] memory bestPools) internal pure returns (uint256 totalOutput) { totalOutput = 0; for (uint256 i = 0; i < bestInputAmounts.length; i++) { uint256 output = IBPool(bestPools[i].pool).calcOutGivenIn( bestPools[i].tokenBalanceIn, bestPools[i].tokenWeightIn, bestPools[i].tokenBalanceOut, bestPools[i].tokenWeightOut, bestInputAmounts[i], bestPools[i].swapFee ); totalOutput = totalOutput.add(output); } return totalOutput; } function calcTotalOutExactOut(uint256[] memory bestInputAmounts, Pool[] memory bestPools) internal pure returns (uint256 totalOutput) { totalOutput = 0; for (uint256 i = 0; i < bestInputAmounts.length; i++) { uint256 output = IBPool(bestPools[i].pool).calcInGivenOut( bestPools[i].tokenBalanceIn, bestPools[i].tokenWeightIn, bestPools[i].tokenBalanceOut, bestPools[i].tokenWeightOut, bestInputAmounts[i], bestPools[i].swapFee ); totalOutput = totalOutput.add(output); } return totalOutput; } /** * @dev Trtansfers `token` from the sender to this conteract. * */ function transferFrom(IXToken token, uint256 amount) internal { require(token.transferFrom(msg.sender, address(this), amount), "ERR_TRANSFER_FAILED"); } /** * @dev Trtansfers protocol swap fee from the sender to this `feeReceiver`. * */ function transferFeeFrom( IXToken token, uint256 amount, bool useUtitlityToken ) internal { if (useUtitlityToken && utilityToken != address(0) && address(utilityTokenFeed) != address(0)) { uint256 discountedFee = utilityTokenFeed.calculateAmount(address(token), amount.div(2)); if (discountedFee > 0) { require( IERC20(utilityToken).transferFrom(msg.sender, feeReceiver, discountedFee), "ERR_FEE_UTILITY_TRANSFER_FAILED" ); } else { require(token.transferFrom(msg.sender, feeReceiver, amount), "ERR_FEE_TRANSFER_FAILED"); } } else { require(token.transferFrom(msg.sender, feeReceiver, amount), "ERR_FEE_TRANSFER_FAILED"); } } function getBalance(IXToken token) internal view returns (uint256) { return token.balanceOf(address(this)); } function transfer(IXToken token, uint256 amount) internal { require(token.transfer(msg.sender, amount), "ERR_TRANSFER_FAILED"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../GSN/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "./ERC1155Receiver.sol"; /** * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived(address, address, uint256[] memory, uint256[] memory, bytes memory) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; interface ISwap { struct Swap { address pool; address tokenIn; address tokenOut; uint256 swapAmount; // tokenInAmount / tokenOutAmount uint256 limitReturnAmount; // minAmountOut / maxAmountIn uint256 maxPrice; } }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title IXToken * @author Protofire * @dev XToken Interface. * */ interface IXToken is IERC20 { /** * @dev Triggers stopped state. * */ function pause() external; /** * @dev Returns to normal state. */ function unpause() external; /** * @dev Sets authorization. * */ function setAuthorization(address authorization_) external; /** * @dev Sets operationsRegistry. * */ function setOperationsRegistry(address operationsRegistry_) external; /** * @dev Sets kya. * */ function setKya(string memory kya_) external; /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * */ function mint(address account, uint256 amount) external; /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * */ function burnFrom(address account, uint256 amount) external; }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; /** * @title IXTokenWrapper * @author Protofire * @dev XTokenWrapper Interface. * */ interface IXTokenWrapper is IERC1155Receiver { /** * @dev Token to xToken registry. */ function tokenToXToken(address _token) external view returns (address); /** * @dev xToken to Token registry. */ function xTokenToToken(address _xToken) external view returns (address); /** * @dev Wraps `_token` into its associated xToken. * */ function wrap(address _token, uint256 _amount) external payable returns (bool); /** * @dev Unwraps `_xToken`. * */ function unwrap(address _xToken, uint256 _amount) external returns (bool); }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; /** * @title IBPool * @author Protofire * @dev Balancer BPool contract interface. * */ interface IBPool { function isPublicSwap() external view returns (bool); function isFinalized() external view returns (bool); function isBound(address t) external view returns (bool); function getNumTokens() external view returns (uint256); function getCurrentTokens() external view returns (address[] memory tokens); function getFinalTokens() external view returns (address[] memory tokens); function getDenormalizedWeight(address token) external view returns (uint256); function getTotalDenormalizedWeight() external view returns (uint256); function getNormalizedWeight(address token) external view returns (uint256); function getBalance(address token) external view returns (uint256); function getSwapFee() external view returns (uint256); function getController() external view returns (address); function setSwapFee(uint256 swapFee) external; function setController(address manager) external; function setPublicSwap(bool public_) external; function finalize() external; function bind( address token, uint256 balance, uint256 denorm ) external; function rebind( address token, uint256 balance, uint256 denorm ) external; function unbind(address token) external; function gulp(address token) external; function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256 spotPrice); function getSpotPriceSansFee(address tokenIn, address tokenOut) external view returns (uint256 spotPrice); function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external; function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) 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 joinswapExternAmountIn( address tokenIn, uint256 tokenAmountIn, uint256 minPoolAmountOut ) external returns (uint256 poolAmountOut); function joinswapPoolAmountOut( address tokenIn, uint256 poolAmountOut, uint256 maxAmountIn ) external returns (uint256 tokenAmountIn); 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 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); function calcSpotPrice( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 swapFee ) external pure returns (uint256 spotPrice); function calcOutGivenIn( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 tokenAmountIn, uint256 swapFee ) external pure returns (uint256 tokenAmountOut); function calcInGivenOut( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 tokenAmountOut, uint256 swapFee ) external pure returns (uint256 tokenAmountIn); function calcPoolOutGivenSingleIn( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 poolSupply, uint256 totalWeight, uint256 tokenAmountIn, uint256 swapFee ) external pure returns (uint256 poolAmountOut); function calcSingleInGivenPoolOut( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountOut, uint256 swapFee ) external pure returns (uint256 tokenAmountIn); function calcSingleOutGivenPoolIn( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountIn, uint256 swapFee ) external pure returns (uint256 tokenAmountOut); function calcPoolInGivenSingleOut( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 tokenAmountOut, uint256 swapFee ) external pure returns (uint256 poolAmountIn); }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; /** * @title IBRegistry * @author Protofire * @dev Balancer BRegistry contract interface. * */ interface IBRegistry { function getBestPoolsWithLimit( address, address, uint256 ) external view returns (address[] memory); }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "../balancer/ISwap.sol"; /** * @title IProtocolFee * @author Protofire * @dev ProtocolFee interface. * */ interface IProtocolFee is ISwap { function batchFee(Swap[] memory swaps, uint256 amountIn) external view returns (uint256); function multihopBatch(Swap[][] memory swapSequences, uint256 amountIn) external view returns (uint256); }
//SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.7.0; /** * @title IUtilTokenPriceFeed * @author Protofire * @dev Interface to be implemented by any UtilityToken price feed logic contract used in the protocol. * */ interface IUTokenPriceFeed { /** * @dev Gets the price a `_asset` in UtilityToken. * * @param _asset address of asset to get the price. */ function getPrice(address _asset) external returns (uint256); /** * @dev Gets how many UtilityToken represents the `_amount` of `_asset`. * * @param _asset address of asset to get the amount. * @param _amount amount of `_asset`. */ function calculateAmount(address _asset, uint256 _amount) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "./IERC1155Receiver.sol"; import "../../introspection/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { constructor() { _registerInterface( ERC1155Receiver(0).onERC1155Received.selector ^ ERC1155Receiver(0).onERC1155BatchReceived.selector ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../../introspection/IERC165.sol"; /** * _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** @dev Handles the receipt of a single ERC1155 token type. This function is called at the end of a `safeTransferFrom` after the balance has been updated. To accept the transfer, this must return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61, or its own function selector). @param operator The address which initiated the transfer (i.e. msg.sender) @param from The address which previously owned the token @param id The ID of the token being transferred @param value The amount of tokens being transferred @param data Additional data with no specified format @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns(bytes4); /** @dev Handles the receipt of a multiple ERC1155 token types. This function is called at the end of a `safeBatchTransferFrom` after the balances have been updated. To accept the transfer(s), this must return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81, or its own function selector). @param operator The address which initiated the batch transfer (i.e. msg.sender) @param from The address which previously owned the token @param ids An array containing ids of each token being transferred (order and length must match values array) @param values An array containing amounts of each token being transferred (order and length must match ids array) @param data Additional data with no specified format @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns(bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_protocolFee","type":"address"},{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"address","name":"_xTokenWrapper","type":"address"},{"internalType":"address","name":"_utilityToken","type":"address"},{"internalType":"address","name":"_utilityTokenFeed","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iquidityProvider","type":"address"},{"indexed":false,"internalType":"address","name":"bpool","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"ExitPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeReceiver","type":"address"}],"name":"FeeReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"address","name":"bpool","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"JoinPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFee","type":"address"}],"name":"ProtocolFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"registry","type":"address"}],"name":"RegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"utilityTokenFeed","type":"address"}],"name":"UtilityTokenFeedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"utilityToken","type":"address"}],"name":"UtilityTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"xTokenWrapper","type":"address"}],"name":"XTokenWrapperSet","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"batchSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"batchSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxPoolAmountIn","type":"uint256"}],"name":"exitswapExternAmountOut","outputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"exitswapPoolAmountIn","outputs":[{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"}],"name":"joinswapExternAmountIn","outputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"}],"name":"joinswapPoolAmountOut","outputs":[{"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[][]","name":"swapSequences","type":"tuple[][]"},{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"multihopBatchSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[][]","name":"swapSequences","type":"tuple[][]"},{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"multihopBatchSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"contract IProtocolFee","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IBRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFee","type":"address"}],"name":"setProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_registry","type":"address"}],"name":"setRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_utilityToken","type":"address"}],"name":"setUtilityToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_utilityTokenFeed","type":"address"}],"name":"setUtilityTokenFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_xTokenWrapper","type":"address"}],"name":"setXTokenWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountIn","type":"uint256"},{"internalType":"uint256","name":"minTotalAmountOut","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"smartSwapExactIn","outputs":[{"internalType":"uint256","name":"totalAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IXToken","name":"tokenIn","type":"address"},{"internalType":"contract IXToken","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"totalAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxTotalAmountIn","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"},{"internalType":"bool","name":"useUtilityToken","type":"bool"}],"name":"smartSwapExactOut","outputs":[{"internalType":"uint256","name":"totalAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"utilityToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"utilityTokenFeed","outputs":[{"internalType":"contract IUTokenPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"viewSplitExactIn","outputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"uint256","name":"totalOutput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"nPools","type":"uint256"}],"name":"viewSplitExactOut","outputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"limitReturnAmount","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"internalType":"struct ISwap.Swap[]","name":"swaps","type":"tuple[]"},{"internalType":"uint256","name":"totalInput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xTokenWrapper","outputs":[{"internalType":"contract IXTokenWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200577338038062005773833981016040819052620000349162000474565b600062000040620000fc565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506200009c6301ffc9a760e01b62000100565b620000ae630271189760e51b62000100565b620000b98662000188565b620000c48562000215565b620000cf8462000299565b620000da836200031d565b620000e582620003a1565b620000f081620003fc565b505050505050620005ee565b3390565b6001600160e01b0319808216141562000160576040805162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015290519081900360640190fd5b6001600160e01b0319166000908152600160208190526040909120805460ff19169091179055565b6001600160a01b038116620001ba5760405162461bcd60e51b8152600401620001b19062000576565b60405180910390fd5b7f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b81604051620001eb9190620004f4565b60405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166200023e5760405162461bcd60e51b8152600401620001b1906200053f565b7f12f03356618ab5217502a4b424ab82e84af7bd05a27dd1d2c10b59a2445acc7f816040516200026f9190620004f4565b60405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116620002c25760405162461bcd60e51b8152600401620001b19062000508565b7fbdf37c276f641820b141429d245add2552b4118c0866e5a78638e3de5ef18d9d81604051620002f39190620004f4565b60405180910390a1600680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038116620003465760405162461bcd60e51b8152600401620001b190620005ad565b7fb7829e66b6a542cac12356b2a24b4f0737b0f19b3a309b0409b7a45cc71902fd81604051620003779190620004f4565b60405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b7f61b3b3859569cecb601513cda243516790683fdd32e445a73da99153c0741b4181604051620003d29190620004f4565b60405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b7ff41b986c5672c286a4b5982affea1a51421eb382f58cb2fe3e84ac25618b3d0e816040516200042d9190620004f4565b60405180910390a1600580546001600160a01b0319166001600160a01b0392909216919091179055565b80516001600160a01b03811681146200046f57600080fd5b919050565b60008060008060008060c087890312156200048d578182fd5b620004988762000457565b9550620004a86020880162000457565b9450620004b86040880162000457565b9350620004c86060880162000457565b9250620004d86080880162000457565b9150620004e860a0880162000457565b90509295509295509295565b6001600160a01b0391909116815260200190565b6020808252601f908201527f666565526563656976657220697320746865207a65726f206164647265737300604082015260600190565b6020808252601f908201527f70726f746f636f6c46656520697320746865207a65726f206164647265737300604082015260600190565b6020808252601c908201527f726567697374727920697320746865207a65726f206164647265737300000000604082015260600190565b60208082526021908201527f78546f6b656e5772617070657220697320746865207a65726f206164647265736040820152607360f81b606082015260800190565b61517580620005fe6000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80638da5cb5b1161010f578063bc197c81116100a2578063e83f663711610071578063e83f6637146103fe578063efdcd97414610411578063f23a6e6114610424578063f2fde38b14610437576101f0565b8063bc197c81146103a5578063c1762b15146103c5578063c667ccbd146103d8578063d7936088146103eb576101f0565b8063a94460f5116100de578063a94460f514610385578063ae86ed891461038d578063b0e21e8a14610395578063b3f006741461039d576101f0565b80638da5cb5b146103445780639013ae081461034c578063a3c1e1361461035f578063a91ee0dc14610372576101f0565b806363ced0921161018757806375da771d1161015657806375da771d146103035780637a15038c146103165780637b103999146103295780638a5c57df14610331576101f0565b806363ced092146102c057806363db0d3d146102d55780636a46cdfc146102e8578063715018a6146102fb576101f0565b8063368bb1fc116101c3578063368bb1fc1461026457806342b81415146102855780634b0f93fb1461029857806351fc218b146102ab576101f0565b806301ffc9a7146101f55780630b13c4101461021e5780632822226f1461023e5780632b1a45c314610251575b600080fd5b610208610203366004614b42565b61044a565b6040516102159190614dc4565b60405180910390f35b61023161022c3660046149b1565b61046d565b6040516102159190615002565b61023161024c366004614b6a565b610ed3565b61023161025f3660046147e9565b610f24565b6102776102723660046147e9565b611232565b604051610215929190614da2565b6102316102933660046147e9565b61160f565b6102776102a63660046147e9565b611950565b6102b3611c76565b6040516102159190614c7b565b6102d36102ce366004614894565b611c85565b005b6102d36102e3366004614708565b611f18565b6102316102f6366004614a2f565b611f7c565b6102d36122cb565b6102316103113660046147e9565b61236d565b610231610324366004614aed565b61256c565b6102b3612851565b6102d361033f366004614894565b612860565b6102b3612c38565b6102d361035a366004614708565b612c47565b6102d361036d366004614708565b612ca8565b6102d3610380366004614708565b612d09565b6102b3612d6a565b6102b3612d79565b6102b3612d88565b6102b3612d97565b6103b86103b3366004614740565b612da6565b6040516102159190614dcf565b6102316103d33660046147e9565b612db7565b6102316103e6366004614b6a565b6130aa565b6102d36103f9366004614708565b6130ef565b61023161040c366004614ab5565b613150565b6102d361041f366004614708565b613435565b6103b861043236600461482e565b613496565b6102d3610445366004614708565b6134a7565b6001600160e01b0319811660009081526001602052604090205460ff165b919050565b6000610479858461359f565b60005b8651811015610df357600087828151811061049357fe5b60200260200101515160011415610717576104ac614456565b8883815181106104b857fe5b60200260200101516000815181106104cc57fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906105149030908690600401614ccc565b60206040518083038186803b15801561052c57600080fd5b505afa158015610540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105649190614bc2565b11156105ee57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b39161059a9190600090600401614cb3565b602060405180830381600087803b1580156105b457600080fd5b505af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190614b26565b505b8251608084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b39261061f92600401614cb3565b602060405180830381600087803b15801561063957600080fd5b505af115801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190614b26565b50806001600160a01b0316637c5e9ea484602001518560800151866040015187606001518860a001516040518663ffffffff1660e01b81526004016106ba959493929190614ce6565b6040805180830381600087803b1580156106d357600080fd5b505af11580156106e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070b9190614bda565b509350610dde92505050565b6000610721614456565b89848151811061072d57fe5b602002602001015160018151811061074157fe5b60209081029190910181015180519181015160405163f8b2cb4f60e01b81529193506001600160a01b0383169163f8d6aed491839163f8b2cb4f9161078891600401614c7b565b60206040518083038186803b1580156107a057600080fd5b505afa1580156107b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d89190614bc2565b6020850151604051634a46c67360e11b81526001600160a01b0386169163948d8ce6916108089190600401614c7b565b60206040518083038186803b15801561082057600080fd5b505afa158015610834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108589190614bc2565b604080870151905163f8b2cb4f60e01b81526001600160a01b0387169163f8b2cb4f916108889190600401614c7b565b60206040518083038186803b1580156108a057600080fd5b505afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190614bc2565b6040808801519051634a46c67360e11b81526001600160a01b0388169163948d8ce6916109089190600401614c7b565b60206040518083038186803b15801561092057600080fd5b505afa158015610934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109589190614bc2565b8760600151876001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b15801561099657600080fd5b505afa1580156109aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ce9190614bc2565b6040518763ffffffff1660e01b81526004016109ef9695949392919061504d565b60206040518083038186803b158015610a0757600080fd5b505afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f9190614bc2565b9250610a49614456565b8b8681518110610a5557fe5b6020026020010151600081518110610a6957fe5b602090810291909101810151908101518151604051636eb1769f60e11b81529293509091600019906001600160a01b0384169063dd62ed3e90610ab29030908690600401614ccc565b60206040518083038186803b158015610aca57600080fd5b505afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190614bc2565b1015610b8d57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b391610b39919060001990600401614cb3565b602060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8b9190614b26565b505b806001600160a01b0316637c5e9ea48460200151856080015186604001518a8860a001516040518663ffffffff1660e01b8152600401610bd1959493929190614ce6565b6040805180830381600087803b158015610bea57600080fd5b505af1158015610bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c229190614bda565b5060208601518651604051636eb1769f60e11b81529299509091600019916001600160a01b0384169163dd62ed3e91610c6091309190600401614ccc565b60206040518083038186803b158015610c7857600080fd5b505afa158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190614bc2565b1015610d3b57855160405163095ea7b360e01b81526001600160a01b0383169163095ea7b391610ce7919060001990600401614cb3565b602060405180830381600087803b158015610d0157600080fd5b505af1158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d399190614b26565b505b846001600160a01b0316637c5e9ea48760200151886080015189604001518a606001518b60a001516040518663ffffffff1660e01b8152600401610d83959493929190614ce6565b6040805180830381600087803b158015610d9c57600080fd5b505af1158015610db0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd49190614bda565b5050505050505050505b610de88184613641565b92505060010161047c565b5082811115610e1d5760405162461bcd60e51b8152600401610e1490614f37565b60405180910390fd5b60035460405163848ed17f60e01b8152610eab9187916001600160a01b039091169063848ed17f90610e55908b908790600401614d3b565b60206040518083038186803b158015610e6d57600080fd5b505afa158015610e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea59190614bc2565b846136a4565b610ebd84610eb886613966565b6139e5565b610eca85610eb887613966565b95945050505050565b600060606000610ee589898988611232565b909250905085811115610f0a5760405162461bcd60e51b8152600401610e1490614f37565b610f17828a8a8988613150565b9998505050505050505050565b6000610f30848361359f565b60405163095ea7b360e01b81526001600160a01b0385169063095ea7b390610f5e9088908690600401614cb3565b602060405180830381600087803b158015610f7857600080fd5b505af1158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb09190614b26565b5060405163036836fd60e51b81526001600160a01b03861690636d06dfa090610fe190879087908790600401614d1a565b602060405180830381600087803b158015610ffb57600080fd5b505af115801561100f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110339190614bc2565b905061104284610eb886613966565b6004805460405163095ea7b360e01b81526001600160a01b038089169363095ea7b39361107493921691889101614cb3565b602060405180830381600087803b15801561108e57600080fd5b505af11580156110a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c69190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a916110f8918991889101614cb3565b602060405180830381600087803b15801561111257600080fd5b505af1158015611126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114a9190614b26565b6111665760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b81526111ef926001600160a01b03909216916327009c7591611199918a9101614c7b565b60206040518083038186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e99190614724565b846139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa33868560405161122293929190614c8f565b60405180910390a1949350505050565b60025460405163bfdbfc4360e01b815260609160009183916001600160a01b03169063bfdbfc439061126c908a908a908990600401614c8f565b60006040518083038186803b15801561128457600080fd5b505afa158015611298573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c09190810190614919565b9050606081516001600160401b03811180156112db57600080fd5b5060405190808252806020026020018201604052801561131557816020015b6113026144a7565b8152602001906001900390816112fa5790505b5090506000805b835181101561138e576113438a8a86848151811061133657fe5b6020026020010151613a13565b83828151811061134f57fe5b602002602001018190525061138483828151811061136957fe5b602002602001015160c001518361364190919063ffffffff16565b915060010161131c565b50606082516001600160401b03811180156113a857600080fd5b506040519080825280602002602001820160405280156113d2578160200160208202803683370190505b5090506000805b845181101561145e57611416846114108784815181106113f557fe5b602002602001015160c001518d613cf390919063ffffffff16565b90613d4c565b83828151811061142257fe5b60200260200101818152505061145483828151811061143d57fe5b60200260200101518361364190919063ffffffff16565b91506001016113d9565b50888110156114b5576114976114748a83613d8e565b8360008151811061148157fe5b602002602001015161364190919063ffffffff16565b826000815181106114a457fe5b6020026020010181815250506114ff565b6114e56114c2828b613d8e565b836000815181106114cf57fe5b6020026020010151613d8e90919063ffffffff16565b826000815181106114f257fe5b6020026020010181815250505b83516001600160401b038111801561151657600080fd5b5060405190808252806020026020018201604052801561155057816020015b61153d614456565b8152602001906001900390816115355790505b50965060005b84518110156115f4576040518060c0016040528086838151811061157657fe5b6020026020010151600001516001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b031681526020018483815181106115ba57fe5b6020026020010151815260200160001981526020016000198152508882815181106115e157fe5b6020908102919091010152600101611556565b506115ff8285613dd0565b9550505050505094509492505050565b600480546040516327009c7560e01b815260009283926001600160a01b0316916327009c7591611641918a9101614c7b565b60206040518083038186803b15801561165957600080fd5b505afa15801561166d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116919190614724565b905061169d818461359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f47693916116ce918591889101614cb3565b602060405180830381600087803b1580156116e857600080fd5b505af11580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190614b26565b61173c5760405162461bcd60e51b8152600401610e1490614e52565b60405162592ce960e31b81526001600160a01b038716906302c967489061176b90889088908890600401614d1a565b602060405180830381600087803b15801561178557600080fd5b505af1158015611799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190614bc2565b91506117c985856139e5565b60006117d58484613d8e565b9050801561190b576004805460405163095ea7b360e01b81526001600160a01b03808b169363095ea7b39361180f93921691869101614cb3565b602060405180830381600087803b15801561182957600080fd5b505af115801561183d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118619190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91611893918b91869101614cb3565b602060405180830381600087803b1580156118ad57600080fd5b505af11580156118c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e59190614b26565b6119015760405162461bcd60e51b8152600401610e1490614ee9565b61190b82826139e5565b7f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb33888560405161193e93929190614c8f565b60405180910390a15050949350505050565b60025460405163bfdbfc4360e01b815260609160009183916001600160a01b03169063bfdbfc439061198a908a908a908990600401614c8f565b60006040518083038186803b1580156119a257600080fd5b505afa1580156119b6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119de9190810190614919565b9050606081516001600160401b03811180156119f957600080fd5b50604051908082528060200260200182016040528015611a3357816020015b611a206144a7565b815260200190600190039081611a185790505b5090506000805b8351811015611a8457611a548a8a86848151811061133657fe5b838281518110611a6057fe5b6020026020010181905250611a7a83828151811061136957fe5b9150600101611a3a565b50606082516001600160401b0381118015611a9e57600080fd5b50604051908082528060200260200182016040528015611ac8578160200160208202803683370190505b5090506000805b8451811015611b1c57611aeb846114108784815181106113f557fe5b838281518110611af757fe5b602002602001018181525050611b1283828151811061143d57fe5b9150600101611acf565b5088811015611b5057611b326114748a83613d8e565b82600081518110611b3f57fe5b602002602001018181525050611b77565b611b5d6114c2828b613d8e565b82600081518110611b6a57fe5b6020026020010181815250505b83516001600160401b0381118015611b8e57600080fd5b50604051908082528060200260200182016040528015611bc857816020015b611bb5614456565b815260200190600190039081611bad5790505b50965060005b8451811015611c6b576040518060c00160405280868381518110611bee57fe5b6020026020010151600001516001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b03168152602001848381518110611c3257fe5b6020026020010151815260200160008152602001600019815250888281518110611c5857fe5b6020908102919091010152600101611bce565b506115ff8285613f20565b6004546001600160a01b031681565b600480546040516327009c7560e01b81526000926001600160a01b03909216916327009c7591611cb791899101614c7b565b60206040518083038186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d079190614724565b9050611d13818561359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f4769391611d44918591899101614cb3565b602060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190614b26565b611db25760405162461bcd60e51b8152600401610e1490614e52565b60405163b02f0b7360e01b81526001600160a01b0386169063b02f0b7390611de29087908790879060040161500b565b600060405180830381600087803b158015611dfc57600080fd5b505af1158015611e10573d6000803e3d6000fd5b505050506060856001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015611e4f57600080fd5b505afa158015611e63573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e8b9190810190614919565b905060005b8151811015611ed457611ecc828281518110611ea857fe5b6020026020010151610eb8848481518110611ebf57fe5b6020026020010151613966565b600101611e90565b507f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb338787604051611f0893929190614c8f565b60405180910390a1505050505050565b611f20614069565b6000546001600160a01b03908116911614611f70576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f798161406d565b50565b6000611f88868561359f565b60005b8751811015612251576000805b898381518110611fa457fe5b60200260200101515181101561223b57611fbc614456565b8a8481518110611fc857fe5b60200260200101518281518110611fdb57fe5b602002602001015190506000816020015190508260011415611fff57606082018490525b8151604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e906120329030908690600401614ccc565b60206040518083038186803b15801561204a57600080fd5b505afa15801561205e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120829190614bc2565b111561210c57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b3916120b89190600090600401614cb3565b602060405180830381600087803b1580156120d257600080fd5b505af11580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a9190614b26565b505b8251606084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b39261213d92600401614cb3565b602060405180830381600087803b15801561215757600080fd5b505af115801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f9190614b26565b50806001600160a01b0316638201aa3f84602001518560600151866040015187608001518860a001516040518663ffffffff1660e01b81526004016121d8959493929190614ce6565b6040805180830381600087803b1580156121f157600080fd5b505af1158015612205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122299190614bda565b5094505060019092019150611f989050565b506122468184613641565b925050600101611f8b565b50828110156122725760405162461bcd60e51b8152600401610e1490614f10565b60035460405163848ed17f60e01b81526122aa9188916001600160a01b039091169063848ed17f90610e55908c908a90600401614d3b565b6122b485826139e5565b6122c186610eb888613966565b9695505050505050565b6122d3614069565b6000546001600160a01b03908116911614612323576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600480546040516327009c7560e01b815260009283926001600160a01b0316916327009c759161239f918a9101614c7b565b60206040518083038186803b1580156123b757600080fd5b505afa1580156123cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ef9190614724565b90506123fb818561359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f476939161242c918591899101614cb3565b602060405180830381600087803b15801561244657600080fd5b505af115801561245a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247e9190614b26565b61249a5760405162461bcd60e51b8152600401610e1490614e52565b6040516346ab38f160e01b81526001600160a01b038716906346ab38f1906124ca90889088908890600401614d1a565b602060405180830381600087803b1580156124e457600080fd5b505af11580156124f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251c9190614bc2565b915061252885836139e5565b7f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb33878660405161255b93929190614c8f565b60405180910390a150949350505050565b6000612578868561359f565b60005b87518110156127f85761258c614456565b88828151811061259857fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906125e09030908690600401614ccc565b60206040518083038186803b1580156125f857600080fd5b505afa15801561260c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126309190614bc2565b11156126ba57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b3916126669190600090600401614cb3565b602060405180830381600087803b15801561268057600080fd5b505af1158015612694573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b89190614b26565b505b8251606084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b3926126eb92600401614cb3565b602060405180830381600087803b15801561270557600080fd5b505af1158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190614b26565b5060208301516060840151604080860151608087015160a08801519251638201aa3f60e01b81526000956001600160a01b03881695638201aa3f956127889592949193600401614ce6565b6040805180830381600087803b1580156127a157600080fd5b505af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190614bda565b5090506127e68187613641565b9550506001909301925061257b915050565b50828110156128195760405162461bcd60e51b8152600401610e1490614f10565b60035460405163886b917560e01b81526122aa9188916001600160a01b039091169063886b917590610e55908c908a90600401614da2565b6002546001600160a01b031681565b6060846001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561289b57600080fd5b505afa1580156128af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128d79190810190614919565b905060005b81518110156129c2576129148282815181106128f457fe5b602002602001015185858481811061290857fe5b9050602002013561359f565b81818151811061292057fe5b60200260200101516001600160a01b031663095ea7b38786868581811061294357fe5b905060200201356040518363ffffffff1660e01b8152600401612967929190614cb3565b602060405180830381600087803b15801561298157600080fd5b505af1158015612995573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b99190614b26565b506001016128dc565b506040516313da703560e21b81526001600160a01b03861690634f69c0d4906129f39087908790879060040161500b565b600060405180830381600087803b158015612a0d57600080fd5b505af1158015612a21573d6000803e3d6000fd5b5050505060005b8151811015612a4857612a40828281518110611ea857fe5b600101612a28565b506004805460405163095ea7b360e01b81526001600160a01b038089169363095ea7b393612a7b93921691899101614cb3565b602060405180830381600087803b158015612a9557600080fd5b505af1158015612aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acd9190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91612aff918991899101614cb3565b602060405180830381600087803b158015612b1957600080fd5b505af1158015612b2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b519190614b26565b612b6d5760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b8152612bf6926001600160a01b03909216916327009c7591612ba0918a9101614c7b565b60206040518083038186803b158015612bb857600080fd5b505afa158015612bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf09190614724565b856139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa338686604051612c2993929190614c8f565b60405180910390a15050505050565b6000546001600160a01b031690565b612c4f614069565b6000546001600160a01b03908116911614612c9f576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f79816140ec565b612cb0614069565b6000546001600160a01b03908116911614612d00576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f7981614145565b612d11614069565b6000546001600160a01b03908116911614612d61576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f79816141c4565b6005546001600160a01b031681565b6007546001600160a01b031681565b6003546001600160a01b031681565b6006546001600160a01b031681565b63bc197c8160e01b95945050505050565b6000612dc3848461359f565b60405163095ea7b360e01b81526001600160a01b0385169063095ea7b390612df19088908790600401614cb3565b602060405180830381600087803b158015612e0b57600080fd5b505af1158015612e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e439190614b26565b50604051635db3427760e01b81526001600160a01b03861690635db3427790612e7490879087908790600401614d1a565b602060405180830381600087803b158015612e8e57600080fd5b505af1158015612ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec69190614bc2565b6004805460405163095ea7b360e01b81529293506001600160a01b038089169363095ea7b393612efc9390921691869101614cb3565b602060405180830381600087803b158015612f1657600080fd5b505af1158015612f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4e9190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91612f80918991869101614cb3565b602060405180830381600087803b158015612f9a57600080fd5b505af1158015612fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd29190614b26565b612fee5760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b8152613077926001600160a01b03909216916327009c7591613021918a9101614c7b565b60206040518083038186803b15801561303957600080fd5b505afa15801561304d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130719190614724565b826139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa33868360405161122293929190614c8f565b6000606060006130bc89898988611950565b9092509050858110156130e15760405162461bcd60e51b8152600401610e1490614f10565b610f17828a8a8a8a8961256c565b6130f7614069565b6000546001600160a01b03908116911614613147576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f7981614243565b600061315c858461359f565b60005b86518110156133dc57613170614456565b87828151811061317c57fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906131c49030908690600401614ccc565b60206040518083038186803b1580156131dc57600080fd5b505afa1580156131f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132149190614bc2565b111561329e57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b39161324a9190600090600401614cb3565b602060405180830381600087803b15801561326457600080fd5b505af1158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c9190614b26565b505b8251608084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b3926132cf92600401614cb3565b602060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190614b26565b5060208301516080840151604080860151606087015160a08801519251631f17a7a960e21b81526000956001600160a01b03881695637c5e9ea49561336c9592949193600401614ce6565b6040805180830381600087803b15801561338557600080fd5b505af1158015613399573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133bd9190614bda565b5090506133ca8187613641565b9550506001909301925061315f915050565b50828111156133fd5760405162461bcd60e51b8152600401610e1490614f37565b60035460405163886b917560e01b8152610eab9187916001600160a01b039091169063886b917590610e55908b908790600401614da2565b61343d614069565b6000546001600160a01b0390811691161461348d576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f798161429c565b63f23a6e6160e01b95945050505050565b6134af614069565b6000546001600160a01b039081169116146134ff576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b6001600160a01b0381166135445760405162461bcd60e51b81526004018080602001828103825260268152602001806150d96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd906135cf90339030908690600401614c8f565b602060405180830381600087803b1580156135e957600080fd5b505af11580156135fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136219190614b26565b61363d5760405162461bcd60e51b8152600401610e1490614f94565b5050565b60008282018381101561369b576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b8080156136bb57506007546001600160a01b031615155b80156136d157506005546001600160a01b031615155b156138bf576005546000906001600160a01b03166329550f97856136f6866002613d4c565b6040518363ffffffff1660e01b8152600401613713929190614cb3565b60206040518083038186803b15801561372b57600080fd5b505afa15801561373f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137639190614bc2565b90508015613817576007546006546040516323b872dd60e01b81526001600160a01b03928316926323b872dd926137a4923392909116908690600401614c8f565b602060405180830381600087803b1580156137be57600080fd5b505af11580156137d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f69190614b26565b6138125760405162461bcd60e51b8152600401610e1490614de4565b6138b9565b6006546040516323b872dd60e01b81526001600160a01b03808716926323b872dd9261384b92339216908890600401614c8f565b602060405180830381600087803b15801561386557600080fd5b505af1158015613879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389d9190614b26565b6138b95760405162461bcd60e51b8152600401610e1490614f5d565b50613961565b6006546040516323b872dd60e01b81526001600160a01b03808616926323b872dd926138f392339216908790600401614c8f565b602060405180830381600087803b15801561390d57600080fd5b505af1158015613921573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139459190614b26565b6139615760405162461bcd60e51b8152600401610e1490614f5d565b505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190613995903090600401614c7b565b60206040518083038186803b1580156139ad57600080fd5b505afa1580156139c1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369e9190614bc2565b60405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb906135cf9033908590600401614cb3565b613a1b6144a7565b60405163f8b2cb4f60e01b815282906000906001600160a01b0383169063f8b2cb4f90613a4c908990600401614c7b565b60206040518083038186803b158015613a6457600080fd5b505afa158015613a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9c9190614bc2565b90506000826001600160a01b031663f8b2cb4f876040518263ffffffff1660e01b8152600401613acc9190614c7b565b60206040518083038186803b158015613ae457600080fd5b505afa158015613af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b1c9190614bc2565b90506000836001600160a01b031663948d8ce6896040518263ffffffff1660e01b8152600401613b4c9190614c7b565b60206040518083038186803b158015613b6457600080fd5b505afa158015613b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9c9190614bc2565b90506000846001600160a01b031663948d8ce6896040518263ffffffff1660e01b8152600401613bcc9190614c7b565b60206040518083038186803b158015613be457600080fd5b505afa158015613bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1c9190614bc2565b90506000856001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b158015613c5957600080fd5b505afa158015613c6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c919190614bc2565b90506000613ca084868561431b565b9050613caa6144a7565b506040805160e0810182526001600160a01b038b16815260208101979097528601939093526060850193909352608084015260a083019190915260c08201529150509392505050565b600082613d025750600061369e565b82820282848281613d0f57fe5b041461369b5760405162461bcd60e51b81526004018080602001828103825260218152602001806150ff6021913960400191505060405180910390fd5b600061369b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061435a565b600061369b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506143fc565b6000805b8351811015613f19576000838281518110613deb57fe5b6020026020010151600001516001600160a01b031663f8d6aed4858481518110613e1157fe5b602002602001015160200151868581518110613e2957fe5b602002602001015160400151878681518110613e4157fe5b602002602001015160600151888781518110613e5957fe5b6020026020010151608001518a8881518110613e7157fe5b60200260200101518a8981518110613e8557fe5b602002602001015160a001516040518763ffffffff1660e01b8152600401613eb29695949392919061504d565b60206040518083038186803b158015613eca57600080fd5b505afa158015613ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f029190614bc2565b9050613f0e8382613641565b925050600101613dd4565b5092915050565b6000805b8351811015613f19576000838281518110613f3b57fe5b6020026020010151600001516001600160a01b031663ba9530a6858481518110613f6157fe5b602002602001015160200151868581518110613f7957fe5b602002602001015160400151878681518110613f9157fe5b602002602001015160600151888781518110613fa957fe5b6020026020010151608001518a8881518110613fc157fe5b60200260200101518a8981518110613fd557fe5b602002602001015160a001516040518763ffffffff1660e01b81526004016140029695949392919061504d565b60206040518083038186803b15801561401a57600080fd5b505afa15801561402e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140529190614bc2565b905061405e8382613641565b925050600101613f24565b3390565b6001600160a01b0381166140935760405162461bcd60e51b8152600401610e1490614e7b565b7f12f03356618ab5217502a4b424ab82e84af7bd05a27dd1d2c10b59a2445acc7f816040516140c29190614c7b565b60405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b7f61b3b3859569cecb601513cda243516790683fdd32e445a73da99153c0741b418160405161411b9190614c7b565b60405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811661416b5760405162461bcd60e51b8152600401610e1490614fc1565b7fb7829e66b6a542cac12356b2a24b4f0737b0f19b3a309b0409b7a45cc71902fd8160405161419a9190614c7b565b60405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166141ea5760405162461bcd60e51b8152600401610e1490614eb2565b7f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b816040516142199190614c7b565b60405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b7ff41b986c5672c286a4b5982affea1a51421eb382f58cb2fe3e84ac25618b3d0e816040516142729190614c7b565b60405180910390a1600580546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166142c25760405162461bcd60e51b8152600401610e1490614e1b565b7fbdf37c276f641820b141429d245add2552b4118c0866e5a78638e3de5ef18d9d816040516142f19190614c7b565b60405180910390a1600680546001600160a01b0319166001600160a01b0392909216919091179055565b6000614352670de0b6b3a76400006114108561434c61433a878a613641565b6114108a670de0b6b3a7640000613cf3565b90613cf3565b949350505050565b600081836143e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156143ab578181015183820152602001614393565b50505050905090810190601f1680156143d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816143f257fe5b0495945050505050565b6000818484111561444e5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156143ab578181015183820152602001614393565b505050900390565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b6040518060e0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8035610468816150b5565b600082601f830112614508578081fd5b813561451b61451682615098565b615075565b818152915060208083019084810160005b8481101561455557614543888484358a0101614560565b8452928201929082019060010161452c565b505050505092915050565b600082601f830112614570578081fd5b813561457e61451682615098565b818152915060208083019084810160c0808502870183018810156145a157600080fd5b6000805b868110156146375782848b0312156145bb578182fd5b604080518481018181106001600160401b03821117156145d757fe5b825285356145e4816150b5565b81526145f18688016144ed565b878201526146008287016144ed565b91810191909152606085810135908201526080808601359082015260a08086013590820152865294840194928201926001016145a5565b5050505050505092915050565b600082601f830112614654578081fd5b813561466261451682615098565b81815291506020808301908481018184028601820187101561468357600080fd5b60005b8481101561455557813584529282019290820190600101614686565b600082601f8301126146b2578081fd5b81356001600160401b038111156146c557fe5b6146d8601f8201601f1916602001615075565b91508082528360208285010111156146ef57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215614719578081fd5b813561369b816150b5565b600060208284031215614735578081fd5b815161369b816150b5565b600080600080600060a08688031215614757578081fd5b8535614762816150b5565b94506020860135614772816150b5565b935060408601356001600160401b038082111561478d578283fd5b61479989838a01614644565b945060608801359150808211156147ae578283fd5b6147ba89838a01614644565b935060808801359150808211156147cf578283fd5b506147dc888289016146a2565b9150509295509295909350565b600080600080608085870312156147fe578384fd5b8435614809816150b5565b93506020850135614819816150b5565b93969395505050506040820135916060013590565b600080600080600060a08688031215614845578081fd5b8535614850816150b5565b94506020860135614860816150b5565b9350604086013592506060860135915060808601356001600160401b03811115614888578182fd5b6147dc888289016146a2565b600080600080606085870312156148a9578182fd5b84356148b4816150b5565b93506020850135925060408501356001600160401b03808211156148d6578384fd5b818701915087601f8301126148e9578384fd5b8135818111156148f7578485fd5b886020808302850101111561490a578485fd5b95989497505060200194505050565b6000602080838503121561492b578182fd5b82516001600160401b03811115614940578283fd5b8301601f81018513614950578283fd5b805161495e61451682615098565b818152838101908385018584028501860189101561497a578687fd5b8694505b838510156149a5578051614991816150b5565b83526001949094019391850191850161497e565b50979650505050505050565b600080600080600060a086880312156149c8578283fd5b85356001600160401b038111156149dd578384fd5b6149e9888289016144f8565b95505060208601356149fa816150b5565b93506040860135614a0a816150b5565b9250606086013591506080860135614a21816150ca565b809150509295509295909350565b60008060008060008060c08789031215614a47578384fd5b86356001600160401b03811115614a5c578485fd5b614a6889828a016144f8565b9650506020870135614a79816150b5565b94506040870135614a89816150b5565b9350606087013592506080870135915060a0870135614aa7816150ca565b809150509295509295509295565b600080600080600060a08688031215614acc578283fd5b85356001600160401b03811115614ae1578384fd5b6149e988828901614560565b60008060008060008060c08789031215614b05578384fd5b86356001600160401b03811115614b1a578485fd5b614a6889828a01614560565b600060208284031215614b37578081fd5b815161369b816150ca565b600060208284031215614b53578081fd5b81356001600160e01b03198116811461369b578182fd5b60008060008060008060c08789031215614b82578384fd5b8635614b8d816150b5565b95506020870135614b9d816150b5565b945060408701359350606087013592506080870135915060a0870135614aa7816150ca565b600060208284031215614bd3578081fd5b5051919050565b60008060408385031215614bec578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b83811015614c7057815180516001600160a01b039081168952848201518116858a015260408083015190911690890152606080820151908901526080808201519089015260a0908101519088015260c09096019590820190600101614c10565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006040820160408352808551808352606085019150602092506060838202860101838801855b83811015614d9057605f19888403018552614d7e838351614bfd565b94860194925090850190600101614d62565b50509290940194909452949350505050565b600060408252614db56040830185614bfd565b90508260208301529392505050565b901515815260200190565b6001600160e01b031991909116815260200190565b6020808252601f908201527f4552525f4645455f5554494c4954595f5452414e534645525f4641494c454400604082015260600190565b6020808252601f908201527f666565526563656976657220697320746865207a65726f206164647265737300604082015260600190565b6020808252600f908201526e11549497d55395d4905417d413d3d3608a1b604082015260600190565b6020808252601f908201527f70726f746f636f6c46656520697320746865207a65726f206164647265737300604082015260600190565b6020808252601c908201527f726567697374727920697320746865207a65726f206164647265737300000000604082015260600190565b6020808252600d908201526c11549497d5d4905417d413d3d3609a1b604082015260600190565b6020808252600d908201526c11549497d31253525517d3d555609a1b604082015260600190565b6020808252600c908201526b22a9292fa624a6a4aa2fa4a760a11b604082015260600190565b60208082526017908201527f4552525f4645455f5452414e534645525f4641494c4544000000000000000000604082015260600190565b60208082526013908201527211549497d514905394d1915497d19052531151606a1b604082015260600190565b60208082526021908201527f78546f6b656e5772617070657220697320746865207a65726f206164647265736040820152607360f81b606082015260800190565b90815260200190565b838152604060208201819052810182905260006001600160fb1b03831115615031578081fd5b6020830280856060850137919091016060019081529392505050565b958652602086019490945260408501929092526060840152608083015260a082015260c00190565b6040518181016001600160401b038111828210171561509057fe5b604052919050565b60006001600160401b038211156150ab57fe5b5060209081020190565b6001600160a01b0381168114611f7957600080fd5b8015158114611f7957600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220e8783311e9e3c448553ee8f646a7d435433e17eec5aaa1a22e4d299d3b5441e464736f6c634300070400330000000000000000000000008133eeb249f0636bba0b8230ba1089a219263c04000000000000000000000000abc2108199f33adf0343ef3a67565313c0aed6c1000000000000000000000000cf6a97d02f9cc47c94de5a4874c32a0182638fb40000000000000000000000002b9dc65253c035eb21778cb3898eab5a0ada0cce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c80638da5cb5b1161010f578063bc197c81116100a2578063e83f663711610071578063e83f6637146103fe578063efdcd97414610411578063f23a6e6114610424578063f2fde38b14610437576101f0565b8063bc197c81146103a5578063c1762b15146103c5578063c667ccbd146103d8578063d7936088146103eb576101f0565b8063a94460f5116100de578063a94460f514610385578063ae86ed891461038d578063b0e21e8a14610395578063b3f006741461039d576101f0565b80638da5cb5b146103445780639013ae081461034c578063a3c1e1361461035f578063a91ee0dc14610372576101f0565b806363ced0921161018757806375da771d1161015657806375da771d146103035780637a15038c146103165780637b103999146103295780638a5c57df14610331576101f0565b806363ced092146102c057806363db0d3d146102d55780636a46cdfc146102e8578063715018a6146102fb576101f0565b8063368bb1fc116101c3578063368bb1fc1461026457806342b81415146102855780634b0f93fb1461029857806351fc218b146102ab576101f0565b806301ffc9a7146101f55780630b13c4101461021e5780632822226f1461023e5780632b1a45c314610251575b600080fd5b610208610203366004614b42565b61044a565b6040516102159190614dc4565b60405180910390f35b61023161022c3660046149b1565b61046d565b6040516102159190615002565b61023161024c366004614b6a565b610ed3565b61023161025f3660046147e9565b610f24565b6102776102723660046147e9565b611232565b604051610215929190614da2565b6102316102933660046147e9565b61160f565b6102776102a63660046147e9565b611950565b6102b3611c76565b6040516102159190614c7b565b6102d36102ce366004614894565b611c85565b005b6102d36102e3366004614708565b611f18565b6102316102f6366004614a2f565b611f7c565b6102d36122cb565b6102316103113660046147e9565b61236d565b610231610324366004614aed565b61256c565b6102b3612851565b6102d361033f366004614894565b612860565b6102b3612c38565b6102d361035a366004614708565b612c47565b6102d361036d366004614708565b612ca8565b6102d3610380366004614708565b612d09565b6102b3612d6a565b6102b3612d79565b6102b3612d88565b6102b3612d97565b6103b86103b3366004614740565b612da6565b6040516102159190614dcf565b6102316103d33660046147e9565b612db7565b6102316103e6366004614b6a565b6130aa565b6102d36103f9366004614708565b6130ef565b61023161040c366004614ab5565b613150565b6102d361041f366004614708565b613435565b6103b861043236600461482e565b613496565b6102d3610445366004614708565b6134a7565b6001600160e01b0319811660009081526001602052604090205460ff165b919050565b6000610479858461359f565b60005b8651811015610df357600087828151811061049357fe5b60200260200101515160011415610717576104ac614456565b8883815181106104b857fe5b60200260200101516000815181106104cc57fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906105149030908690600401614ccc565b60206040518083038186803b15801561052c57600080fd5b505afa158015610540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105649190614bc2565b11156105ee57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b39161059a9190600090600401614cb3565b602060405180830381600087803b1580156105b457600080fd5b505af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190614b26565b505b8251608084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b39261061f92600401614cb3565b602060405180830381600087803b15801561063957600080fd5b505af115801561064d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106719190614b26565b50806001600160a01b0316637c5e9ea484602001518560800151866040015187606001518860a001516040518663ffffffff1660e01b81526004016106ba959493929190614ce6565b6040805180830381600087803b1580156106d357600080fd5b505af11580156106e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061070b9190614bda565b509350610dde92505050565b6000610721614456565b89848151811061072d57fe5b602002602001015160018151811061074157fe5b60209081029190910181015180519181015160405163f8b2cb4f60e01b81529193506001600160a01b0383169163f8d6aed491839163f8b2cb4f9161078891600401614c7b565b60206040518083038186803b1580156107a057600080fd5b505afa1580156107b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d89190614bc2565b6020850151604051634a46c67360e11b81526001600160a01b0386169163948d8ce6916108089190600401614c7b565b60206040518083038186803b15801561082057600080fd5b505afa158015610834573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108589190614bc2565b604080870151905163f8b2cb4f60e01b81526001600160a01b0387169163f8b2cb4f916108889190600401614c7b565b60206040518083038186803b1580156108a057600080fd5b505afa1580156108b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d89190614bc2565b6040808801519051634a46c67360e11b81526001600160a01b0388169163948d8ce6916109089190600401614c7b565b60206040518083038186803b15801561092057600080fd5b505afa158015610934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109589190614bc2565b8760600151876001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b15801561099657600080fd5b505afa1580156109aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ce9190614bc2565b6040518763ffffffff1660e01b81526004016109ef9695949392919061504d565b60206040518083038186803b158015610a0757600080fd5b505afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f9190614bc2565b9250610a49614456565b8b8681518110610a5557fe5b6020026020010151600081518110610a6957fe5b602090810291909101810151908101518151604051636eb1769f60e11b81529293509091600019906001600160a01b0384169063dd62ed3e90610ab29030908690600401614ccc565b60206040518083038186803b158015610aca57600080fd5b505afa158015610ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b029190614bc2565b1015610b8d57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b391610b39919060001990600401614cb3565b602060405180830381600087803b158015610b5357600080fd5b505af1158015610b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8b9190614b26565b505b806001600160a01b0316637c5e9ea48460200151856080015186604001518a8860a001516040518663ffffffff1660e01b8152600401610bd1959493929190614ce6565b6040805180830381600087803b158015610bea57600080fd5b505af1158015610bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c229190614bda565b5060208601518651604051636eb1769f60e11b81529299509091600019916001600160a01b0384169163dd62ed3e91610c6091309190600401614ccc565b60206040518083038186803b158015610c7857600080fd5b505afa158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190614bc2565b1015610d3b57855160405163095ea7b360e01b81526001600160a01b0383169163095ea7b391610ce7919060001990600401614cb3565b602060405180830381600087803b158015610d0157600080fd5b505af1158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d399190614b26565b505b846001600160a01b0316637c5e9ea48760200151886080015189604001518a606001518b60a001516040518663ffffffff1660e01b8152600401610d83959493929190614ce6565b6040805180830381600087803b158015610d9c57600080fd5b505af1158015610db0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd49190614bda565b5050505050505050505b610de88184613641565b92505060010161047c565b5082811115610e1d5760405162461bcd60e51b8152600401610e1490614f37565b60405180910390fd5b60035460405163848ed17f60e01b8152610eab9187916001600160a01b039091169063848ed17f90610e55908b908790600401614d3b565b60206040518083038186803b158015610e6d57600080fd5b505afa158015610e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea59190614bc2565b846136a4565b610ebd84610eb886613966565b6139e5565b610eca85610eb887613966565b95945050505050565b600060606000610ee589898988611232565b909250905085811115610f0a5760405162461bcd60e51b8152600401610e1490614f37565b610f17828a8a8988613150565b9998505050505050505050565b6000610f30848361359f565b60405163095ea7b360e01b81526001600160a01b0385169063095ea7b390610f5e9088908690600401614cb3565b602060405180830381600087803b158015610f7857600080fd5b505af1158015610f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb09190614b26565b5060405163036836fd60e51b81526001600160a01b03861690636d06dfa090610fe190879087908790600401614d1a565b602060405180830381600087803b158015610ffb57600080fd5b505af115801561100f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110339190614bc2565b905061104284610eb886613966565b6004805460405163095ea7b360e01b81526001600160a01b038089169363095ea7b39361107493921691889101614cb3565b602060405180830381600087803b15801561108e57600080fd5b505af11580156110a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c69190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a916110f8918991889101614cb3565b602060405180830381600087803b15801561111257600080fd5b505af1158015611126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114a9190614b26565b6111665760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b81526111ef926001600160a01b03909216916327009c7591611199918a9101614c7b565b60206040518083038186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e99190614724565b846139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa33868560405161122293929190614c8f565b60405180910390a1949350505050565b60025460405163bfdbfc4360e01b815260609160009183916001600160a01b03169063bfdbfc439061126c908a908a908990600401614c8f565b60006040518083038186803b15801561128457600080fd5b505afa158015611298573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c09190810190614919565b9050606081516001600160401b03811180156112db57600080fd5b5060405190808252806020026020018201604052801561131557816020015b6113026144a7565b8152602001906001900390816112fa5790505b5090506000805b835181101561138e576113438a8a86848151811061133657fe5b6020026020010151613a13565b83828151811061134f57fe5b602002602001018190525061138483828151811061136957fe5b602002602001015160c001518361364190919063ffffffff16565b915060010161131c565b50606082516001600160401b03811180156113a857600080fd5b506040519080825280602002602001820160405280156113d2578160200160208202803683370190505b5090506000805b845181101561145e57611416846114108784815181106113f557fe5b602002602001015160c001518d613cf390919063ffffffff16565b90613d4c565b83828151811061142257fe5b60200260200101818152505061145483828151811061143d57fe5b60200260200101518361364190919063ffffffff16565b91506001016113d9565b50888110156114b5576114976114748a83613d8e565b8360008151811061148157fe5b602002602001015161364190919063ffffffff16565b826000815181106114a457fe5b6020026020010181815250506114ff565b6114e56114c2828b613d8e565b836000815181106114cf57fe5b6020026020010151613d8e90919063ffffffff16565b826000815181106114f257fe5b6020026020010181815250505b83516001600160401b038111801561151657600080fd5b5060405190808252806020026020018201604052801561155057816020015b61153d614456565b8152602001906001900390816115355790505b50965060005b84518110156115f4576040518060c0016040528086838151811061157657fe5b6020026020010151600001516001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b031681526020018483815181106115ba57fe5b6020026020010151815260200160001981526020016000198152508882815181106115e157fe5b6020908102919091010152600101611556565b506115ff8285613dd0565b9550505050505094509492505050565b600480546040516327009c7560e01b815260009283926001600160a01b0316916327009c7591611641918a9101614c7b565b60206040518083038186803b15801561165957600080fd5b505afa15801561166d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116919190614724565b905061169d818461359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f47693916116ce918591889101614cb3565b602060405180830381600087803b1580156116e857600080fd5b505af11580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190614b26565b61173c5760405162461bcd60e51b8152600401610e1490614e52565b60405162592ce960e31b81526001600160a01b038716906302c967489061176b90889088908890600401614d1a565b602060405180830381600087803b15801561178557600080fd5b505af1158015611799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117bd9190614bc2565b91506117c985856139e5565b60006117d58484613d8e565b9050801561190b576004805460405163095ea7b360e01b81526001600160a01b03808b169363095ea7b39361180f93921691869101614cb3565b602060405180830381600087803b15801561182957600080fd5b505af115801561183d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118619190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91611893918b91869101614cb3565b602060405180830381600087803b1580156118ad57600080fd5b505af11580156118c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e59190614b26565b6119015760405162461bcd60e51b8152600401610e1490614ee9565b61190b82826139e5565b7f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb33888560405161193e93929190614c8f565b60405180910390a15050949350505050565b60025460405163bfdbfc4360e01b815260609160009183916001600160a01b03169063bfdbfc439061198a908a908a908990600401614c8f565b60006040518083038186803b1580156119a257600080fd5b505afa1580156119b6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119de9190810190614919565b9050606081516001600160401b03811180156119f957600080fd5b50604051908082528060200260200182016040528015611a3357816020015b611a206144a7565b815260200190600190039081611a185790505b5090506000805b8351811015611a8457611a548a8a86848151811061133657fe5b838281518110611a6057fe5b6020026020010181905250611a7a83828151811061136957fe5b9150600101611a3a565b50606082516001600160401b0381118015611a9e57600080fd5b50604051908082528060200260200182016040528015611ac8578160200160208202803683370190505b5090506000805b8451811015611b1c57611aeb846114108784815181106113f557fe5b838281518110611af757fe5b602002602001018181525050611b1283828151811061143d57fe5b9150600101611acf565b5088811015611b5057611b326114748a83613d8e565b82600081518110611b3f57fe5b602002602001018181525050611b77565b611b5d6114c2828b613d8e565b82600081518110611b6a57fe5b6020026020010181815250505b83516001600160401b0381118015611b8e57600080fd5b50604051908082528060200260200182016040528015611bc857816020015b611bb5614456565b815260200190600190039081611bad5790505b50965060005b8451811015611c6b576040518060c00160405280868381518110611bee57fe5b6020026020010151600001516001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b03168152602001848381518110611c3257fe5b6020026020010151815260200160008152602001600019815250888281518110611c5857fe5b6020908102919091010152600101611bce565b506115ff8285613f20565b6004546001600160a01b031681565b600480546040516327009c7560e01b81526000926001600160a01b03909216916327009c7591611cb791899101614c7b565b60206040518083038186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d079190614724565b9050611d13818561359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f4769391611d44918591899101614cb3565b602060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190614b26565b611db25760405162461bcd60e51b8152600401610e1490614e52565b60405163b02f0b7360e01b81526001600160a01b0386169063b02f0b7390611de29087908790879060040161500b565b600060405180830381600087803b158015611dfc57600080fd5b505af1158015611e10573d6000803e3d6000fd5b505050506060856001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b158015611e4f57600080fd5b505afa158015611e63573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e8b9190810190614919565b905060005b8151811015611ed457611ecc828281518110611ea857fe5b6020026020010151610eb8848481518110611ebf57fe5b6020026020010151613966565b600101611e90565b507f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb338787604051611f0893929190614c8f565b60405180910390a1505050505050565b611f20614069565b6000546001600160a01b03908116911614611f70576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f798161406d565b50565b6000611f88868561359f565b60005b8751811015612251576000805b898381518110611fa457fe5b60200260200101515181101561223b57611fbc614456565b8a8481518110611fc857fe5b60200260200101518281518110611fdb57fe5b602002602001015190506000816020015190508260011415611fff57606082018490525b8151604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e906120329030908690600401614ccc565b60206040518083038186803b15801561204a57600080fd5b505afa15801561205e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120829190614bc2565b111561210c57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b3916120b89190600090600401614cb3565b602060405180830381600087803b1580156120d257600080fd5b505af11580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a9190614b26565b505b8251606084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b39261213d92600401614cb3565b602060405180830381600087803b15801561215757600080fd5b505af115801561216b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218f9190614b26565b50806001600160a01b0316638201aa3f84602001518560600151866040015187608001518860a001516040518663ffffffff1660e01b81526004016121d8959493929190614ce6565b6040805180830381600087803b1580156121f157600080fd5b505af1158015612205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122299190614bda565b5094505060019092019150611f989050565b506122468184613641565b925050600101611f8b565b50828110156122725760405162461bcd60e51b8152600401610e1490614f10565b60035460405163848ed17f60e01b81526122aa9188916001600160a01b039091169063848ed17f90610e55908c908a90600401614d3b565b6122b485826139e5565b6122c186610eb888613966565b9695505050505050565b6122d3614069565b6000546001600160a01b03908116911614612323576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600480546040516327009c7560e01b815260009283926001600160a01b0316916327009c759161239f918a9101614c7b565b60206040518083038186803b1580156123b757600080fd5b505afa1580156123cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ef9190614724565b90506123fb818561359f565b600480546040516339f4769360e01b81526001600160a01b03909116916339f476939161242c918591899101614cb3565b602060405180830381600087803b15801561244657600080fd5b505af115801561245a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247e9190614b26565b61249a5760405162461bcd60e51b8152600401610e1490614e52565b6040516346ab38f160e01b81526001600160a01b038716906346ab38f1906124ca90889088908890600401614d1a565b602060405180830381600087803b1580156124e457600080fd5b505af11580156124f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251c9190614bc2565b915061252885836139e5565b7f2206cb302a65b0877ae38d30e1ad81ec174734a0709a9664e91f77cac85303fb33878660405161255b93929190614c8f565b60405180910390a150949350505050565b6000612578868561359f565b60005b87518110156127f85761258c614456565b88828151811061259857fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906125e09030908690600401614ccc565b60206040518083038186803b1580156125f857600080fd5b505afa15801561260c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126309190614bc2565b11156126ba57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b3916126669190600090600401614cb3565b602060405180830381600087803b15801561268057600080fd5b505af1158015612694573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b89190614b26565b505b8251606084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b3926126eb92600401614cb3565b602060405180830381600087803b15801561270557600080fd5b505af1158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190614b26565b5060208301516060840151604080860151608087015160a08801519251638201aa3f60e01b81526000956001600160a01b03881695638201aa3f956127889592949193600401614ce6565b6040805180830381600087803b1580156127a157600080fd5b505af11580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190614bda565b5090506127e68187613641565b9550506001909301925061257b915050565b50828110156128195760405162461bcd60e51b8152600401610e1490614f10565b60035460405163886b917560e01b81526122aa9188916001600160a01b039091169063886b917590610e55908c908a90600401614da2565b6002546001600160a01b031681565b6060846001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561289b57600080fd5b505afa1580156128af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128d79190810190614919565b905060005b81518110156129c2576129148282815181106128f457fe5b602002602001015185858481811061290857fe5b9050602002013561359f565b81818151811061292057fe5b60200260200101516001600160a01b031663095ea7b38786868581811061294357fe5b905060200201356040518363ffffffff1660e01b8152600401612967929190614cb3565b602060405180830381600087803b15801561298157600080fd5b505af1158015612995573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b99190614b26565b506001016128dc565b506040516313da703560e21b81526001600160a01b03861690634f69c0d4906129f39087908790879060040161500b565b600060405180830381600087803b158015612a0d57600080fd5b505af1158015612a21573d6000803e3d6000fd5b5050505060005b8151811015612a4857612a40828281518110611ea857fe5b600101612a28565b506004805460405163095ea7b360e01b81526001600160a01b038089169363095ea7b393612a7b93921691899101614cb3565b602060405180830381600087803b158015612a9557600080fd5b505af1158015612aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acd9190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91612aff918991899101614cb3565b602060405180830381600087803b158015612b1957600080fd5b505af1158015612b2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b519190614b26565b612b6d5760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b8152612bf6926001600160a01b03909216916327009c7591612ba0918a9101614c7b565b60206040518083038186803b158015612bb857600080fd5b505afa158015612bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf09190614724565b856139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa338686604051612c2993929190614c8f565b60405180910390a15050505050565b6000546001600160a01b031690565b612c4f614069565b6000546001600160a01b03908116911614612c9f576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f79816140ec565b612cb0614069565b6000546001600160a01b03908116911614612d00576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f7981614145565b612d11614069565b6000546001600160a01b03908116911614612d61576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f79816141c4565b6005546001600160a01b031681565b6007546001600160a01b031681565b6003546001600160a01b031681565b6006546001600160a01b031681565b63bc197c8160e01b95945050505050565b6000612dc3848461359f565b60405163095ea7b360e01b81526001600160a01b0385169063095ea7b390612df19088908790600401614cb3565b602060405180830381600087803b158015612e0b57600080fd5b505af1158015612e1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e439190614b26565b50604051635db3427760e01b81526001600160a01b03861690635db3427790612e7490879087908790600401614d1a565b602060405180830381600087803b158015612e8e57600080fd5b505af1158015612ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec69190614bc2565b6004805460405163095ea7b360e01b81529293506001600160a01b038089169363095ea7b393612efc9390921691869101614cb3565b602060405180830381600087803b158015612f1657600080fd5b505af1158015612f2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4e9190614b26565b5060048054604051635f9bb63d60e11b81526001600160a01b039091169163bf376c7a91612f80918991869101614cb3565b602060405180830381600087803b158015612f9a57600080fd5b505af1158015612fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd29190614b26565b612fee5760405162461bcd60e51b8152600401610e1490614ee9565b600480546040516327009c7560e01b8152613077926001600160a01b03909216916327009c7591613021918a9101614c7b565b60206040518083038186803b15801561303957600080fd5b505afa15801561304d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130719190614724565b826139e5565b7f4671f31d5ada3c01641120fcda075c42345f98aecbc27a921204235adfd602aa33868360405161122293929190614c8f565b6000606060006130bc89898988611950565b9092509050858110156130e15760405162461bcd60e51b8152600401610e1490614f10565b610f17828a8a8a8a8961256c565b6130f7614069565b6000546001600160a01b03908116911614613147576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f7981614243565b600061315c858461359f565b60005b86518110156133dc57613170614456565b87828151811061317c57fe5b602090810291909101810151908101518151604051636eb1769f60e11b815292935090916000906001600160a01b0384169063dd62ed3e906131c49030908690600401614ccc565b60206040518083038186803b1580156131dc57600080fd5b505afa1580156131f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132149190614bc2565b111561329e57825160405163095ea7b360e01b81526001600160a01b0384169163095ea7b39161324a9190600090600401614cb3565b602060405180830381600087803b15801561326457600080fd5b505af1158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c9190614b26565b505b8251608084015160405163095ea7b360e01b81526001600160a01b0385169263095ea7b3926132cf92600401614cb3565b602060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133219190614b26565b5060208301516080840151604080860151606087015160a08801519251631f17a7a960e21b81526000956001600160a01b03881695637c5e9ea49561336c9592949193600401614ce6565b6040805180830381600087803b15801561338557600080fd5b505af1158015613399573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133bd9190614bda565b5090506133ca8187613641565b9550506001909301925061315f915050565b50828111156133fd5760405162461bcd60e51b8152600401610e1490614f37565b60035460405163886b917560e01b8152610eab9187916001600160a01b039091169063886b917590610e55908b908790600401614da2565b61343d614069565b6000546001600160a01b0390811691161461348d576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b611f798161429c565b63f23a6e6160e01b95945050505050565b6134af614069565b6000546001600160a01b039081169116146134ff576040805162461bcd60e51b81526020600482018190526024820152600080516020615120833981519152604482015290519081900360640190fd5b6001600160a01b0381166135445760405162461bcd60e51b81526004018080602001828103825260268152602001806150d96026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6040516323b872dd60e01b81526001600160a01b038316906323b872dd906135cf90339030908690600401614c8f565b602060405180830381600087803b1580156135e957600080fd5b505af11580156135fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136219190614b26565b61363d5760405162461bcd60e51b8152600401610e1490614f94565b5050565b60008282018381101561369b576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b8080156136bb57506007546001600160a01b031615155b80156136d157506005546001600160a01b031615155b156138bf576005546000906001600160a01b03166329550f97856136f6866002613d4c565b6040518363ffffffff1660e01b8152600401613713929190614cb3565b60206040518083038186803b15801561372b57600080fd5b505afa15801561373f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137639190614bc2565b90508015613817576007546006546040516323b872dd60e01b81526001600160a01b03928316926323b872dd926137a4923392909116908690600401614c8f565b602060405180830381600087803b1580156137be57600080fd5b505af11580156137d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f69190614b26565b6138125760405162461bcd60e51b8152600401610e1490614de4565b6138b9565b6006546040516323b872dd60e01b81526001600160a01b03808716926323b872dd9261384b92339216908890600401614c8f565b602060405180830381600087803b15801561386557600080fd5b505af1158015613879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389d9190614b26565b6138b95760405162461bcd60e51b8152600401610e1490614f5d565b50613961565b6006546040516323b872dd60e01b81526001600160a01b03808616926323b872dd926138f392339216908790600401614c8f565b602060405180830381600087803b15801561390d57600080fd5b505af1158015613921573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139459190614b26565b6139615760405162461bcd60e51b8152600401610e1490614f5d565b505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190613995903090600401614c7b565b60206040518083038186803b1580156139ad57600080fd5b505afa1580156139c1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369e9190614bc2565b60405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb906135cf9033908590600401614cb3565b613a1b6144a7565b60405163f8b2cb4f60e01b815282906000906001600160a01b0383169063f8b2cb4f90613a4c908990600401614c7b565b60206040518083038186803b158015613a6457600080fd5b505afa158015613a78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9c9190614bc2565b90506000826001600160a01b031663f8b2cb4f876040518263ffffffff1660e01b8152600401613acc9190614c7b565b60206040518083038186803b158015613ae457600080fd5b505afa158015613af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b1c9190614bc2565b90506000836001600160a01b031663948d8ce6896040518263ffffffff1660e01b8152600401613b4c9190614c7b565b60206040518083038186803b158015613b6457600080fd5b505afa158015613b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9c9190614bc2565b90506000846001600160a01b031663948d8ce6896040518263ffffffff1660e01b8152600401613bcc9190614c7b565b60206040518083038186803b158015613be457600080fd5b505afa158015613bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1c9190614bc2565b90506000856001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b158015613c5957600080fd5b505afa158015613c6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c919190614bc2565b90506000613ca084868561431b565b9050613caa6144a7565b506040805160e0810182526001600160a01b038b16815260208101979097528601939093526060850193909352608084015260a083019190915260c08201529150509392505050565b600082613d025750600061369e565b82820282848281613d0f57fe5b041461369b5760405162461bcd60e51b81526004018080602001828103825260218152602001806150ff6021913960400191505060405180910390fd5b600061369b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061435a565b600061369b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506143fc565b6000805b8351811015613f19576000838281518110613deb57fe5b6020026020010151600001516001600160a01b031663f8d6aed4858481518110613e1157fe5b602002602001015160200151868581518110613e2957fe5b602002602001015160400151878681518110613e4157fe5b602002602001015160600151888781518110613e5957fe5b6020026020010151608001518a8881518110613e7157fe5b60200260200101518a8981518110613e8557fe5b602002602001015160a001516040518763ffffffff1660e01b8152600401613eb29695949392919061504d565b60206040518083038186803b158015613eca57600080fd5b505afa158015613ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f029190614bc2565b9050613f0e8382613641565b925050600101613dd4565b5092915050565b6000805b8351811015613f19576000838281518110613f3b57fe5b6020026020010151600001516001600160a01b031663ba9530a6858481518110613f6157fe5b602002602001015160200151868581518110613f7957fe5b602002602001015160400151878681518110613f9157fe5b602002602001015160600151888781518110613fa957fe5b6020026020010151608001518a8881518110613fc157fe5b60200260200101518a8981518110613fd557fe5b602002602001015160a001516040518763ffffffff1660e01b81526004016140029695949392919061504d565b60206040518083038186803b15801561401a57600080fd5b505afa15801561402e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140529190614bc2565b905061405e8382613641565b925050600101613f24565b3390565b6001600160a01b0381166140935760405162461bcd60e51b8152600401610e1490614e7b565b7f12f03356618ab5217502a4b424ab82e84af7bd05a27dd1d2c10b59a2445acc7f816040516140c29190614c7b565b60405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b7f61b3b3859569cecb601513cda243516790683fdd32e445a73da99153c0741b418160405161411b9190614c7b565b60405180910390a1600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811661416b5760405162461bcd60e51b8152600401610e1490614fc1565b7fb7829e66b6a542cac12356b2a24b4f0737b0f19b3a309b0409b7a45cc71902fd8160405161419a9190614c7b565b60405180910390a1600480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166141ea5760405162461bcd60e51b8152600401610e1490614eb2565b7f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b816040516142199190614c7b565b60405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b7ff41b986c5672c286a4b5982affea1a51421eb382f58cb2fe3e84ac25618b3d0e816040516142729190614c7b565b60405180910390a1600580546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166142c25760405162461bcd60e51b8152600401610e1490614e1b565b7fbdf37c276f641820b141429d245add2552b4118c0866e5a78638e3de5ef18d9d816040516142f19190614c7b565b60405180910390a1600680546001600160a01b0319166001600160a01b0392909216919091179055565b6000614352670de0b6b3a76400006114108561434c61433a878a613641565b6114108a670de0b6b3a7640000613cf3565b90613cf3565b949350505050565b600081836143e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156143ab578181015183820152602001614393565b50505050905090810190601f1680156143d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816143f257fe5b0495945050505050565b6000818484111561444e5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156143ab578181015183820152602001614393565b505050900390565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b6040518060e0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8035610468816150b5565b600082601f830112614508578081fd5b813561451b61451682615098565b615075565b818152915060208083019084810160005b8481101561455557614543888484358a0101614560565b8452928201929082019060010161452c565b505050505092915050565b600082601f830112614570578081fd5b813561457e61451682615098565b818152915060208083019084810160c0808502870183018810156145a157600080fd5b6000805b868110156146375782848b0312156145bb578182fd5b604080518481018181106001600160401b03821117156145d757fe5b825285356145e4816150b5565b81526145f18688016144ed565b878201526146008287016144ed565b91810191909152606085810135908201526080808601359082015260a08086013590820152865294840194928201926001016145a5565b5050505050505092915050565b600082601f830112614654578081fd5b813561466261451682615098565b81815291506020808301908481018184028601820187101561468357600080fd5b60005b8481101561455557813584529282019290820190600101614686565b600082601f8301126146b2578081fd5b81356001600160401b038111156146c557fe5b6146d8601f8201601f1916602001615075565b91508082528360208285010111156146ef57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215614719578081fd5b813561369b816150b5565b600060208284031215614735578081fd5b815161369b816150b5565b600080600080600060a08688031215614757578081fd5b8535614762816150b5565b94506020860135614772816150b5565b935060408601356001600160401b038082111561478d578283fd5b61479989838a01614644565b945060608801359150808211156147ae578283fd5b6147ba89838a01614644565b935060808801359150808211156147cf578283fd5b506147dc888289016146a2565b9150509295509295909350565b600080600080608085870312156147fe578384fd5b8435614809816150b5565b93506020850135614819816150b5565b93969395505050506040820135916060013590565b600080600080600060a08688031215614845578081fd5b8535614850816150b5565b94506020860135614860816150b5565b9350604086013592506060860135915060808601356001600160401b03811115614888578182fd5b6147dc888289016146a2565b600080600080606085870312156148a9578182fd5b84356148b4816150b5565b93506020850135925060408501356001600160401b03808211156148d6578384fd5b818701915087601f8301126148e9578384fd5b8135818111156148f7578485fd5b886020808302850101111561490a578485fd5b95989497505060200194505050565b6000602080838503121561492b578182fd5b82516001600160401b03811115614940578283fd5b8301601f81018513614950578283fd5b805161495e61451682615098565b818152838101908385018584028501860189101561497a578687fd5b8694505b838510156149a5578051614991816150b5565b83526001949094019391850191850161497e565b50979650505050505050565b600080600080600060a086880312156149c8578283fd5b85356001600160401b038111156149dd578384fd5b6149e9888289016144f8565b95505060208601356149fa816150b5565b93506040860135614a0a816150b5565b9250606086013591506080860135614a21816150ca565b809150509295509295909350565b60008060008060008060c08789031215614a47578384fd5b86356001600160401b03811115614a5c578485fd5b614a6889828a016144f8565b9650506020870135614a79816150b5565b94506040870135614a89816150b5565b9350606087013592506080870135915060a0870135614aa7816150ca565b809150509295509295509295565b600080600080600060a08688031215614acc578283fd5b85356001600160401b03811115614ae1578384fd5b6149e988828901614560565b60008060008060008060c08789031215614b05578384fd5b86356001600160401b03811115614b1a578485fd5b614a6889828a01614560565b600060208284031215614b37578081fd5b815161369b816150ca565b600060208284031215614b53578081fd5b81356001600160e01b03198116811461369b578182fd5b60008060008060008060c08789031215614b82578384fd5b8635614b8d816150b5565b95506020870135614b9d816150b5565b945060408701359350606087013592506080870135915060a0870135614aa7816150ca565b600060208284031215614bd3578081fd5b5051919050565b60008060408385031215614bec578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b83811015614c7057815180516001600160a01b039081168952848201518116858a015260408083015190911690890152606080820151908901526080808201519089015260a0908101519088015260c09096019590820190600101614c10565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006040820160408352808551808352606085019150602092506060838202860101838801855b83811015614d9057605f19888403018552614d7e838351614bfd565b94860194925090850190600101614d62565b50509290940194909452949350505050565b600060408252614db56040830185614bfd565b90508260208301529392505050565b901515815260200190565b6001600160e01b031991909116815260200190565b6020808252601f908201527f4552525f4645455f5554494c4954595f5452414e534645525f4641494c454400604082015260600190565b6020808252601f908201527f666565526563656976657220697320746865207a65726f206164647265737300604082015260600190565b6020808252600f908201526e11549497d55395d4905417d413d3d3608a1b604082015260600190565b6020808252601f908201527f70726f746f636f6c46656520697320746865207a65726f206164647265737300604082015260600190565b6020808252601c908201527f726567697374727920697320746865207a65726f206164647265737300000000604082015260600190565b6020808252600d908201526c11549497d5d4905417d413d3d3609a1b604082015260600190565b6020808252600d908201526c11549497d31253525517d3d555609a1b604082015260600190565b6020808252600c908201526b22a9292fa624a6a4aa2fa4a760a11b604082015260600190565b60208082526017908201527f4552525f4645455f5452414e534645525f4641494c4544000000000000000000604082015260600190565b60208082526013908201527211549497d514905394d1915497d19052531151606a1b604082015260600190565b60208082526021908201527f78546f6b656e5772617070657220697320746865207a65726f206164647265736040820152607360f81b606082015260800190565b90815260200190565b838152604060208201819052810182905260006001600160fb1b03831115615031578081fd5b6020830280856060850137919091016060019081529392505050565b958652602086019490945260408501929092526060840152608083015260a082015260c00190565b6040518181016001600160401b038111828210171561509057fe5b604052919050565b60006001600160401b038211156150ab57fe5b5060209081020190565b6001600160a01b0381168114611f7957600080fd5b8015158114611f7957600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220e8783311e9e3c448553ee8f646a7d435433e17eec5aaa1a22e4d299d3b5441e464736f6c63430007040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008133eeb249f0636bba0b8230ba1089a219263c04000000000000000000000000abc2108199f33adf0343ef3a67565313c0aed6c1000000000000000000000000cf6a97d02f9cc47c94de5a4874c32a0182638fb40000000000000000000000002b9dc65253c035eb21778cb3898eab5a0ada0cce00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _registry (address): 0x8133EEB249F0636bba0B8230Ba1089a219263c04
Arg [1] : _protocolFee (address): 0xabC2108199F33ADF0343ef3A67565313C0Aed6C1
Arg [2] : _feeReceiver (address): 0xCf6a97d02f9Cc47C94dE5a4874C32a0182638fb4
Arg [3] : _xTokenWrapper (address): 0x2b9dc65253c035Eb21778cB3898eab5A0AdA0cCe
Arg [4] : _utilityToken (address): 0x0000000000000000000000000000000000000000
Arg [5] : _utilityTokenFeed (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000008133eeb249f0636bba0b8230ba1089a219263c04
Arg [1] : 000000000000000000000000abc2108199f33adf0343ef3a67565313c0aed6c1
Arg [2] : 000000000000000000000000cf6a97d02f9cc47c94de5a4874c32a0182638fb4
Arg [3] : 0000000000000000000000002b9dc65253c035eb21778cb3898eab5a0ada0cce
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.