Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,580 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Burn Exact And S... | 19557253 | 282 days ago | IN | 0 ETH | 0.00393748 | ||||
Swap Exact ETH F... | 19483685 | 293 days ago | IN | 0.01 ETH | 0.00765926 | ||||
Burn Exact And S... | 19232253 | 328 days ago | IN | 0 ETH | 0.0039407 | ||||
Burn Exact And S... | 18542961 | 424 days ago | IN | 0 ETH | 0.01378781 | ||||
Burn Exact And S... | 18455560 | 437 days ago | IN | 0 ETH | 0.00313944 | ||||
Swap Exact Token... | 17498024 | 571 days ago | IN | 0 ETH | 0.00224486 | ||||
Burn And Swap Fo... | 17457863 | 577 days ago | IN | 0 ETH | 0.00539262 | ||||
Burn Exact And S... | 17164593 | 618 days ago | IN | 0 ETH | 0.00948034 | ||||
Burn Exact And S... | 17092989 | 628 days ago | IN | 0 ETH | 0.00986949 | ||||
Burn Exact And S... | 16878560 | 658 days ago | IN | 0 ETH | 0.00443008 | ||||
Burn Exact And S... | 16878548 | 658 days ago | IN | 0 ETH | 0.00402463 | ||||
Burn Exact And S... | 16878511 | 658 days ago | IN | 0 ETH | 0.00470373 | ||||
Burn Exact And S... | 16878510 | 658 days ago | IN | 0 ETH | 0.00365839 | ||||
Burn Exact And S... | 16878507 | 658 days ago | IN | 0 ETH | 0.00393138 | ||||
Burn Exact And S... | 16878394 | 658 days ago | IN | 0 ETH | 0.00447369 | ||||
Burn Exact And S... | 16878388 | 658 days ago | IN | 0 ETH | 0.00363845 | ||||
Swap ETH For Tok... | 16875953 | 659 days ago | IN | 0.01714071 ETH | 0.00311858 | ||||
Swap ETH For Tok... | 16875949 | 659 days ago | IN | 0.01759275 ETH | 0.00318219 | ||||
Swap ETH For Tok... | 16875333 | 659 days ago | IN | 0.01395695 ETH | 0.00328762 | ||||
Swap ETH For Tok... | 16875329 | 659 days ago | IN | 0.01254466 ETH | 0.0042021 | ||||
Swap ETH For Tok... | 16875324 | 659 days ago | IN | 0.01259809 ETH | 0.00324008 | ||||
Swap ETH For Tok... | 16875203 | 659 days ago | IN | 0.01258547 ETH | 0.00405097 | ||||
Swap ETH For Tok... | 16875151 | 659 days ago | IN | 0.02299658 ETH | 0.0030567 | ||||
Swap ETH For Tok... | 16875104 | 659 days ago | IN | 0.0106712 ETH | 0.00327301 | ||||
Swap ETH For Tok... | 16875085 | 659 days ago | IN | 0.01527291 ETH | 0.00324797 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19557253 | 282 days ago | 0.29467762 ETH | ||||
19557253 | 282 days ago | 0.29467762 ETH | ||||
19483685 | 293 days ago | 0.01 ETH | ||||
19232253 | 328 days ago | 0.07864238 ETH | ||||
19232253 | 328 days ago | 0.07864238 ETH | ||||
18542961 | 424 days ago | 0.00000007 ETH | ||||
18542961 | 424 days ago | 0.00000007 ETH | ||||
18455560 | 437 days ago | 0.00548903 ETH | ||||
18455560 | 437 days ago | 0.00548903 ETH | ||||
17498024 | 571 days ago | 0.60933087 ETH | ||||
17498024 | 571 days ago | 0.60933087 ETH | ||||
17164593 | 618 days ago | 0.09124878 ETH | ||||
17164593 | 618 days ago | 0.09124878 ETH | ||||
17092989 | 628 days ago | 0.00000103 ETH | ||||
17092989 | 628 days ago | 0.00000103 ETH | ||||
16878560 | 658 days ago | 0.02034351 ETH | ||||
16878560 | 658 days ago | 0.02034351 ETH | ||||
16878548 | 658 days ago | 0.02063111 ETH | ||||
16878548 | 658 days ago | 0.02063111 ETH | ||||
16878510 | 658 days ago | 0.02209614 ETH | ||||
16878510 | 658 days ago | 0.02209614 ETH | ||||
16878507 | 658 days ago | 0.02996772 ETH | ||||
16878507 | 658 days ago | 0.02996772 ETH | ||||
16878394 | 658 days ago | 0.01742385 ETH | ||||
16878394 | 658 days ago | 0.01742385 ETH |
Loading...
Loading
Contract Name:
IndexedNarwhalRouter
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "./NarwhalRouter.sol"; import "./BMath.sol"; import "./interfaces/IIndexPool.sol"; import "./interfaces/IERC20.sol"; import "./libraries/TransferHelper.sol"; contract IndexedNarwhalRouter is NarwhalRouter, BMath { using TokenInfo for bytes32; using TokenInfo for address; using TransferHelper for address; using SafeMath for uint256; constructor( address _uniswapFactory, address _sushiswapFactory, address _weth ) NarwhalRouter(_uniswapFactory, _sushiswapFactory, _weth) {} /** ========== Mint Single: Exact In ========== */ /** * @dev Swaps ether for each token in `path` using their Uniswap pairs, * then mints at least `minPoolAmountOut` pool tokens from `indexPool`. * * @param path Array of encoded tokens to swap using the Narwhal router. * @param indexPool Address of the index pool to mint tokens from. * @param minPoolAmountOut Amount of pool tokens that must be received to not revert. */ function swapExactETHForTokensAndMint( bytes32[] calldata path, address indexPool, uint minPoolAmountOut ) external payable returns (uint poolAmountOut) { require(path[0].readToken() == address(weth), "NRouter: INVALID_PATH"); uint256[] memory amounts = getAmountsOut(path, msg.value); weth.deposit{value: amounts[0]}(); address(weth).safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, address(this)); uint amountOut = amounts[amounts.length - 1]; return _mintExactIn( path[path.length - 1].readToken(), amountOut, indexPool, minPoolAmountOut ); } /** * @dev Swaps a token for each other token in `path` using their Uniswap pairs, * then mints at least `minPoolAmountOut` pool tokens from `indexPool`. * * @param amountIn Amount of the first token in `path` to swap. * @param path Array of encoded tokens to swap using the Narwhal router. * @param indexPool Address of the index pool to mint tokens from. * @param minPoolAmountOut Amount of pool tokens that must be received to not revert. */ function swapExactTokensForTokensAndMint( uint amountIn, bytes32[] calldata path, address indexPool, uint minPoolAmountOut ) external returns (uint poolAmountOut) { uint256[] memory amounts = getAmountsOut(path, amountIn); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); uint amountOut = amounts[amounts.length - 1]; return _mintExactIn( path[path.length - 1].readToken(), amountOut, indexPool, minPoolAmountOut ); } function _mintExactIn( address tokenIn, uint amountIn, address indexPool, uint minPoolAmountOut ) internal returns (uint poolAmountOut) { TransferHelper.safeApprove(tokenIn, indexPool, amountIn); poolAmountOut = IIndexPool(indexPool).joinswapExternAmountIn( tokenIn, amountIn, minPoolAmountOut ); TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut); } /** ========== Burn Single: Exact In ========== */ /** * @dev Redeems `poolAmountIn` pool tokens for the first token in `path` * and swaps it to at least `minAmountOut` of the last token in `path`. * * @param indexPool Address of the index pool to burn tokens from. * @param poolAmountIn Amount of pool tokens to burn. * @param path Array of encoded tokens to swap using the Narwhal router. * @param minAmountOut Amount of last token in `path` that must be received to not revert. * @return amountOut Amount of output tokens received. */ function burnExactAndSwapForTokens( address indexPool, uint poolAmountIn, bytes32[] calldata path, uint minAmountOut ) external returns (uint amountOut) { amountOut = _burnExactAndSwap( indexPool, poolAmountIn, path, minAmountOut, msg.sender ); } /** * @dev Redeems `poolAmountIn` pool tokens for the first token in `path` * and swaps it to at least `minAmountOut` ether. * * @param indexPool Address of the index pool to burn tokens from. * @param poolAmountIn Amount of pool tokens to burn. * @param path Array of encoded tokens to swap using the Narwhal router. * @param minAmountOut Amount of ether that must be received to not revert. * @return amountOut Amount of ether received. */ function burnExactAndSwapForETH( address indexPool, uint poolAmountIn, bytes32[] calldata path, uint minAmountOut ) external returns (uint amountOut) { require(path[path.length - 1].readToken() == address(weth), "NRouter: INVALID_PATH"); amountOut = _burnExactAndSwap( indexPool, poolAmountIn, path, minAmountOut, address(this) ); IWETH(weth).withdraw(amountOut); TransferHelper.safeTransferETH(msg.sender, amountOut); } function _burnExactAndSwap( address indexPool, uint poolAmountIn, bytes32[] memory path, uint minAmountOut, address recipient ) internal returns (uint amountOut) { // Transfer the pool tokens to the router. TransferHelper.safeTransferFrom( indexPool, msg.sender, address(this), poolAmountIn ); // Burn the pool tokens for the first token in `path`. uint redeemedAmountOut = IIndexPool(indexPool).exitswapPoolAmountIn( path[0].readToken(), poolAmountIn, 0 ); // Calculate the swap amounts for the redeemed amount of the first token in `path`. uint[] memory amounts = getAmountsOut(path, redeemedAmountOut); amountOut = amounts[amounts.length - 1]; require(amountOut >= minAmountOut, "NRouter: MIN_OUT"); // Transfer the redeemed tokens to the first Uniswap pair. TransferHelper.safeTransfer( path[0].readToken(), pairFor(path[0], path[1]), amounts[0] ); // Execute the routed swaps and send the output tokens to `recipient`. _swap(amounts, path, recipient); } /** ========== Mint Single: Exact Out ========== */ /** * @dev Swaps ether for each token in `path` through Uniswap, * then mints `poolAmountOut` pool tokens from `indexPool`. * * @param path Array of encoded tokens to swap using the Narwhal router. * @param indexPool Address of the index pool to mint tokens from. * @param poolAmountOut Amount of pool tokens that must be received to not revert. */ function swapETHForTokensAndMintExact( bytes32[] calldata path, address indexPool, uint poolAmountOut ) external payable { address swapTokenOut = path[path.length - 1].readToken(); uint amountOut = _tokenInGivenPoolOut(indexPool, swapTokenOut, poolAmountOut); require(path[0].readToken() == address(weth), "INVALID_PATH"); uint[] memory amounts = getAmountsIn(path, amountOut); require(amounts[0] <= msg.value, "NRouter: MAX_IN"); weth.deposit{value: amounts[0]}(); address(weth).safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, address(this)); // refund dust eth, if any if (msg.value > amounts[0]) { TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); } return _mintExactOut( swapTokenOut, amountOut, indexPool, poolAmountOut ); } /** * @dev Swaps a token for each other token in `path` through Uniswap, * then mints at least `poolAmountOut` pool tokens from `indexPool`. * * @param amountInMax Maximum amount of the first token in `path` to give. * @param path Array of encoded tokens to swap using the Narwhal router. * @param indexPool Address of the index pool to mint tokens from. * @param poolAmountOut Amount of pool tokens that must be received to not revert. */ function swapTokensForTokensAndMintExact( uint amountInMax, bytes32[] calldata path, address indexPool, uint poolAmountOut ) external { address swapTokenOut = path[path.length - 1].readToken(); uint amountOut = _tokenInGivenPoolOut(indexPool, swapTokenOut, poolAmountOut); uint[] memory amounts = getAmountsIn(path, amountOut); require(amounts[0] <= amountInMax, "NRouter: MAX_IN"); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); _mintExactOut( swapTokenOut, amountOut, indexPool, poolAmountOut ); } function _mintExactOut( address tokenIn, uint amountIn, address indexPool, uint poolAmountOut ) internal { TransferHelper.safeApprove(tokenIn, indexPool, amountIn); IIndexPool(indexPool).joinswapPoolAmountOut( tokenIn, poolAmountOut, amountIn ); TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut); } function _tokenInGivenPoolOut( address indexPool, address tokenIn, uint256 poolAmountOut ) internal view returns (uint256 amountIn) { IIndexPool.Record memory record = IIndexPool(indexPool).getTokenRecord(tokenIn); if (!record.ready) { uint256 minimumBalance = IIndexPool(indexPool).getMinimumBalance(tokenIn); uint256 realToMinRatio = bdiv( bsub(minimumBalance, record.balance), minimumBalance ); uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio); record.balance = minimumBalance; record.denorm = uint96(badd(MIN_WEIGHT, weightPremium)); } uint256 totalSupply = IERC20(indexPool).totalSupply(); uint256 totalWeight = IIndexPool(indexPool).getTotalDenormalizedWeight(); uint256 swapFee = IIndexPool(indexPool).getSwapFee(); return calcSingleInGivenPoolOut( record.balance, record.denorm, totalSupply, totalWeight, poolAmountOut, swapFee ); } /** ========== Burn Single: Exact Out ========== */ /** * @dev Redeems up to `poolAmountInMax` pool tokens for the first token in `path` * and swaps it to exactly `tokenAmountOut` of the last token in `path`. * * @param indexPool Address of the index pool to burn tokens from. * @param poolAmountInMax Maximum amount of pool tokens to burn. * @param path Array of encoded tokens to swap using the Narwhal router. * @param tokenAmountOut Amount of last token in `path` to receive. * @return poolAmountIn Amount of pool tokens burned. */ function burnAndSwapForExactTokens( address indexPool, uint poolAmountInMax, bytes32[] calldata path, uint tokenAmountOut ) external returns (uint poolAmountIn) { poolAmountIn = _burnAndSwapForExact( indexPool, poolAmountInMax, path, tokenAmountOut, msg.sender ); } /** * @dev Redeems up to `poolAmountInMax` pool tokens for the first token in `path` * and swaps it to exactly `ethAmountOut` ether. * * @param indexPool Address of the index pool to burn tokens from. * @param poolAmountInMax Maximum amount of pool tokens to burn. * @param path Array of encoded tokens to swap using the Narwhal router. * @param ethAmountOut Amount of eth to receive. * @return poolAmountIn Amount of pool tokens burned. */ function burnAndSwapForExactETH( address indexPool, uint poolAmountInMax, bytes32[] calldata path, uint ethAmountOut ) external returns (uint poolAmountIn) { require(path[path.length - 1].readToken() == address(weth), "NRouter: INVALID_PATH"); poolAmountIn = _burnAndSwapForExact( indexPool, poolAmountInMax, path, ethAmountOut, address(this) ); IWETH(weth).withdraw(ethAmountOut); TransferHelper.safeTransferETH(msg.sender, ethAmountOut); } function _burnAndSwapForExact( address indexPool, uint poolAmountInMax, bytes32[] memory path, uint tokenAmountOut, address recipient ) internal returns (uint poolAmountIn) { // Transfer the maximum pool tokens to the router. indexPool.safeTransferFrom( msg.sender, address(this), poolAmountInMax ); // Calculate the swap amounts for `tokenAmountOut` of the last token in `path`. uint[] memory amounts = getAmountsIn(path, tokenAmountOut); // Burn the pool tokens for the exact amount of the first token in `path`. poolAmountIn = IIndexPool(indexPool).exitswapExternAmountOut( path[0].readToken(), amounts[0], poolAmountInMax ); // Transfer the redeemed tokens to the first Uniswap pair. TransferHelper.safeTransfer( path[0].readToken(), pairFor(path[0], path[1]), amounts[0] ); // Execute the routed swaps and send the output tokens to `recipient`. _swap(amounts, path, recipient); // Return any unburned pool tokens to the caller. indexPool.safeTransfer( msg.sender, poolAmountInMax.sub(poolAmountIn) ); } /** ========== Mint All: Exact Out ========== */ /** * @dev Swaps an input token for every underlying token in an index pool, * then mints `poolAmountOut` pool tokens from the pool. * * Up to one intermediary token may be provided in `intermediaries` for each * underlying token in the index pool. * * If a null address is provided as an intermediary, the input token will be * swapped directly for the output token. * * `intermediaries` is an encoded Narwhal path with a one-byte prefix indicating * whether the first swap should use sushiswap. * * @param indexPool Address of the index pool to mint tokens with. * @param intermediaries Encoded Narwhal tokens array with a one-byte prefix * indicating whether the swap to the underlying token should use sushiswap. * @param poolAmountOut Amount of index pool tokens to mint. * @param tokenIn Token to buy the underlying tokens with. * @param amountInMax Maximumm amount of `tokenIn` to spend. * @return Amount of `tokenIn` spent. */ function swapTokensForAllTokensAndMintExact( address indexPool, bytes32[] calldata intermediaries, uint256 poolAmountOut, address tokenIn, uint256 amountInMax ) external returns (uint256) { uint256 remainder = amountInMax; address[] memory tokens = IIndexPool(indexPool).getCurrentTokens(); require( tokens.length == intermediaries.length, "NRouter: ARR_LEN" ); tokenIn.safeTransferFrom(msg.sender, address(this), amountInMax); uint256[] memory amountsToPool = new uint256[](tokens.length); uint256 ratio = bdiv(poolAmountOut, IERC20(indexPool).totalSupply()); // Reserve 3 slots in memory for the addresses bytes32[] memory path = new bytes32[](3); path[0] = tokenIn.pack(false); for (uint256 i = 0; i < tokens.length; i++) { (amountsToPool[i], remainder) = _handleMintInput( indexPool, intermediaries[i], tokens[i], path, ratio, remainder ); } IIndexPool(indexPool).joinPool(poolAmountOut, amountsToPool); TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut); if (remainder > 0) { tokenIn.safeTransfer(msg.sender, remainder); } return amountInMax.sub(remainder); } /** * @dev Swaps ether for every underlying token in an index pool, * then mints `poolAmountOut` pool tokens from the pool. * * Up to one intermediary token may be provided in `intermediaries` for each * underlying token in the index pool. * * If a null address is provided as an intermediary, the input token will be * swapped directly for the output token. * * `intermediaries` is an encoded Narwhal path with a one-byte prefix indicating * whether the first swap should use sushiswap. * * @param indexPool Address of the index pool to mint tokens with. * @param intermediaries Encoded Narwhal tokens array with a one-byte prefix * indicating whether the swap to the underlying token should use sushiswap. * @param poolAmountOut Amount of index pool tokens to mint. * @return Amount of ether spent. */ function swapETHForAllTokensAndMintExact( address indexPool, bytes32[] calldata intermediaries, uint256 poolAmountOut ) external payable returns (uint) { uint256 remainder = msg.value; IWETH(weth).deposit{value: msg.value}(); address[] memory tokens = IIndexPool(indexPool).getCurrentTokens(); require(tokens.length == intermediaries.length, "NRouter: ARR_LEN"); uint256[] memory amountsToPool = new uint256[](tokens.length); uint256 ratio = bdiv(poolAmountOut, IERC20(indexPool).totalSupply()); // Reserve 3 slots in memory for the addresses bytes32[] memory path = new bytes32[](3); path[0] = address(weth).pack(false); for (uint256 i = 0; i < tokens.length; i++) { (amountsToPool[i], remainder) = _handleMintInput( indexPool, intermediaries[i], tokens[i], path, ratio, remainder ); } IIndexPool(indexPool).joinPool(poolAmountOut, amountsToPool); TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut); if (remainder > 0) { IWETH(weth).withdraw(remainder); TransferHelper.safeTransferETH(msg.sender, remainder); } return msg.value.sub(remainder); } function _handleMintInput( address indexPool, bytes32 intermediate, address poolToken, bytes32[] memory path, uint256 poolRatio, uint256 amountInMax ) internal returns (uint256 amountToPool, uint256 remainder) { address tokenIn = path[0].readToken(); uint256 usedBalance = IIndexPool(indexPool).getUsedBalance(poolToken); amountToPool = bmul(poolRatio, usedBalance); if (tokenIn == poolToken) { remainder = amountInMax.sub(amountToPool, "NRouter: MAX_IN"); } else { bool sushiFirst; assembly { sushiFirst := shr(168, intermediate) intermediate := and( 0x0000000000000000000000ffffffffffffffffffffffffffffffffffffffffff, intermediate ) } path[0] = tokenIn.pack(sushiFirst); if (intermediate == bytes32(0)) { // If no intermediate token is given, set path length to 2 so the other // functions will not use the 3rd address. assembly { mstore(path, 2) } // It doesn't matter whether a token is set to use sushi or not // if it is the last token in the list. path[1] = poolToken.pack(false); } else { // If an intermediary is given, set path length to 3 so the other // functions will use all addresses. assembly { mstore(path, 3) } path[1] = intermediate; path[2] = poolToken.pack(false); } uint[] memory amounts = getAmountsIn(path, amountToPool); remainder = amountInMax.sub(amounts[0], "NRouter: MAX_IN"); tokenIn.safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, address(this)); } poolToken.safeApprove(indexPool, amountToPool); } /** ========== Burn All: Exact In ========== */ /** * @dev Burns `poolAmountOut` for all the underlying tokens in a pool, then * swaps each of them on Uniswap for at least `minAmountOut` of `tokenOut`. * * Up to one intermediary token may be provided in `intermediaries` for each * underlying token in the index pool. * * If a null address is provided as an intermediary, the input token will be * swapped directly for the output token. * * @param indexPool Address of the index pool to burn tokens from. * @param minAmountsOut Minimum amount of each underlying token that must be * received from the pool to not revert. * @param intermediaries Encoded Narwhal tokens array with a one-byte prefix * indicating whether the swap to the underlying token should use sushiswap. * @param poolAmountIn Amount of index pool tokens to burn. * @param tokenOut Address of the token to buy. * @param minAmountOut Minimum amount of `tokenOut` that must be received to * not revert. * @return amountOutTotal Amount of `tokenOut` received. */ function burnForAllTokensAndSwapForTokens( address indexPool, uint256[] calldata minAmountsOut, bytes32[] calldata intermediaries, uint256 poolAmountIn, address tokenOut, uint256 minAmountOut ) external returns (uint256 amountOutTotal) { amountOutTotal = _burnForAllTokensAndSwap( indexPool, tokenOut, minAmountsOut, intermediaries, poolAmountIn, minAmountOut, msg.sender ); } /** * @dev Burns `poolAmountOut` for all the underlying tokens in a pool, then * swaps each of them on Uniswap for at least `minAmountOut` ether. * * Up to one intermediary token may be provided in `intermediaries` for each * underlying token in the index pool. * * If a null address is provided as an intermediary, the input token will be * swapped directly for the output token. * * @param indexPool Address of the index pool to burn tokens from. * @param minAmountsOut Minimum amount of each underlying token that must be * received from the pool to not revert. * @param intermediaries Encoded Narwhal tokens array with a one-byte prefix * indicating whether the swap to the underlying token should use sushiswap. * @param poolAmountIn Amount of index pool tokens to burn. * @param minAmountOut Minimum amount of ether that must be received to * not revert. * @return amountOutTotal Amount of ether received. */ function burnForAllTokensAndSwapForETH( address indexPool, uint256[] calldata minAmountsOut, bytes32[] calldata intermediaries, uint256 poolAmountIn, uint256 minAmountOut ) external returns (uint amountOutTotal) { amountOutTotal = _burnForAllTokensAndSwap( indexPool, address(weth), minAmountsOut, intermediaries, poolAmountIn, minAmountOut, address(this) ); IWETH(weth).withdraw(amountOutTotal); TransferHelper.safeTransferETH(msg.sender, amountOutTotal); } function _burnForAllTokensAndSwap( address indexPool, address tokenOut, uint256[] calldata minAmountsOut, bytes32[] calldata intermediaries, uint256 poolAmountIn, uint256 minAmountOut, address recipient ) internal returns (uint amountOutTotal) { // Transfer the pool tokens from the caller. TransferHelper.safeTransferFrom(indexPool, msg.sender, address(this), poolAmountIn); address[] memory tokens = IIndexPool(indexPool).getCurrentTokens(); require( intermediaries.length == tokens.length && minAmountsOut.length == tokens.length, "IndexedUniswapRouterBurner: BAD_ARRAY_LENGTH" ); IIndexPool(indexPool).exitPool(poolAmountIn, minAmountsOut); // Reserve 3 slots in memory for the addresses bytes32[] memory path = new bytes32[](3); for (uint256 i = 0; i < tokens.length; i++) { uint amountOut = _handleBurnOutput( tokens[i], intermediaries[i], tokenOut, path, recipient ); amountOutTotal = amountOutTotal.add(amountOut); } require(amountOutTotal >= minAmountOut, "NRouter: MIN_OUT"); } function _handleBurnOutput( address tokenIn, bytes32 intermediate, address tokenOut, bytes32[] memory path, address recipient ) internal returns (uint amountOut) { uint256 _balance = IERC20(tokenIn).balanceOf(address(this)); if (tokenIn == tokenOut) { amountOut = _balance; if (recipient != address(this)) { tokenIn.safeTransfer(recipient, _balance); } } else { bool sushiFirst; assembly { sushiFirst := shr(168, intermediate) intermediate := and( 0x0000000000000000000000ffffffffffffffffffffffffffffffffffffffffff, intermediate ) } path[0] = tokenIn.pack(sushiFirst); if (intermediate == bytes32(0)) { // If no intermediate token is given, set path length to 2 so the other // functions will not use the 3rd address. assembly { mstore(path, 2) } // It doesn't matter whether a token is set to use sushi or not // if it is the last token in the list. path[1] = tokenOut.pack(false); } else { // If an intermediary is given, set path length to 3 so the other // functions will use all addresses. assembly { mstore(path, 3) } path[1] = intermediate; path[2] = tokenOut.pack(false); } uint[] memory amounts = getAmountsOut(path, _balance); tokenIn.safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, recipient); amountOut = amounts[amounts.length - 1]; } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; import "./BNum.sol"; contract BMath is BNum { function calcSingleInGivenPoolOut( uint256 tokenBalanceIn, uint256 tokenWeightIn, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountOut, uint256 swapFee ) internal pure returns (uint256 tokenAmountIn) { uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight); uint256 newPoolSupply = badd(poolSupply, poolAmountOut); uint256 poolRatio = bdiv(newPoolSupply, poolSupply); //uint newBalTi = poolRatio^(1/weightTi) * balTi; uint256 boo = bdiv(BONE, normalizedWeight); uint256 tokenInRatio = bpow(poolRatio, boo); uint256 newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn); uint256 tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn); // Do reverse order of fees charged in joinswap_ExternAmountIn, this way // ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ``` //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ; uint256 zar = bmul(bsub(BONE, normalizedWeight), swapFee); tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar)); return tokenAmountIn; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; contract BNum { uint256 internal constant BONE = 1e18; uint256 internal constant MIN_BPOW_BASE = 1 wei; uint256 internal constant MAX_BPOW_BASE = (2 * BONE) - 1 wei; uint256 internal constant BPOW_PRECISION = BONE / 10**10; uint256 internal constant MIN_WEIGHT = BONE / 4; function btoi(uint256 a) internal pure returns (uint256) { return a / BONE; } function bfloor(uint256 a) internal pure returns (uint256) { return btoi(a) * BONE; } function badd(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "ERR_ADD_OVERFLOW"); return c; } function bsub(uint256 a, uint256 b) internal pure returns (uint256) { (uint256 c, bool flag) = bsubSign(a, b); require(!flag, "ERR_SUB_UNDERFLOW"); return c; } function bsubSign(uint256 a, uint256 b) internal pure returns (uint256, bool) { if (a >= b) { return (a - b, false); } else { return (b - a, true); } } function bmul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c0 = a * b; require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW"); uint256 c1 = c0 + (BONE / 2); require(c1 >= c0, "ERR_MUL_OVERFLOW"); uint256 c2 = c1 / BONE; return c2; } function bdiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "ERR_DIV_ZERO"); uint256 c0 = a * BONE; require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow uint256 c1 = c0 + (b / 2); require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require uint256 c2 = c1 / b; return c2; } // DSMath.wpow function bpowi(uint256 a, uint256 n) internal pure returns (uint256) { uint256 z = n % 2 != 0 ? a : BONE; for (n /= 2; n != 0; n /= 2) { a = bmul(a, a); if (n % 2 != 0) { z = bmul(z, a); } } return z; } // Compute b^(e.w) by splitting it into (b^e)*(b^0.w). // Use `bpowi` for `b^e` and `bpowK` for k iterations // of approximation of b^0.w function bpow(uint256 base, uint256 exp) internal pure returns (uint256) { require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW"); require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH"); uint256 whole = bfloor(exp); uint256 remain = bsub(exp, whole); uint256 wholePow = bpowi(base, btoi(whole)); if (remain == 0) { return wholePow; } uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION); return bmul(wholePow, partialResult); } function bpowApprox( uint256 base, uint256 exp, uint256 precision ) internal pure returns (uint256) { // term 0: uint256 a = exp; (uint256 x, bool xneg) = bsubSign(base, BONE); uint256 term = BONE; uint256 sum = term; bool negative = false; // term(k) = numer / denom // = (product(a - i - 1, i=1-->k) * x^k) / (k!) // each iteration, multiply previous term by (a-(k-1)) * x / k // continue until term is less than precision for (uint256 i = 1; term >= precision; i++) { uint256 bigK = i * BONE; (uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE)); term = bmul(term, bmul(c, x)); term = bdiv(term, bigK); if (term == 0) break; if (xneg) negative = !negative; if (cneg) negative = !negative; if (negative) { sum = bsub(sum, term); } else { sum = badd(sum, term); } } return sum; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./interfaces/IUniswapV2Pair.sol"; import "./interfaces/IWETH.sol"; import "./libraries/SafeMath.sol"; import "./libraries/TokenInfo.sol"; contract Narwhal { using SafeMath for uint256; using TokenInfo for bytes32; address public immutable uniswapFactory; address public immutable sushiswapFactory; IWETH public immutable weth; /** ========== Constructor ========== */ constructor( address _uniswapFactory, address _sushiswapFactory, address _weth ) { uniswapFactory = _uniswapFactory; sushiswapFactory = _sushiswapFactory; weth = IWETH(_weth); } /** ========== Fallback ========== */ receive() external payable { assert(msg.sender == address(weth)); // only accept ETH via fallback from the WETH contract } /** ========== Swaps ========== */ // requires the initial amount to have already been sent to the first pair function _swap(uint[] memory amounts, bytes32[] memory path, address recipient) internal { for (uint i; i < path.length - 1; i++) { (bytes32 input, bytes32 output) = (path[i], path[i + 1]); uint amountOut = amounts[i + 1]; (uint amount0Out, uint amount1Out) = (input < output) ? (uint(0), amountOut) : (amountOut, uint(0)); address to = i < path.length - 2 ? pairFor(output, path[i + 2]) : recipient; IUniswapV2Pair(pairFor(input, output)).swap( amount0Out, amount1Out, to, new bytes(0) ); } } /** ========== Pair Calculation & Sorting ========== */ // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); } function zeroForOne(bytes32 tokenA, bytes32 tokenB) internal pure returns (bool) { return tokenA < tokenB; } // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(bytes32 tokenA, bytes32 tokenB) internal pure returns (bytes32 token0, bytes32 token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != bytes32(0), "UniswapV2Library: ZERO_ADDRESS"); } function calculateUniPair(address token0, address token1 ) internal view returns (address pair) { pair = address( uint256( keccak256( abi.encodePacked( hex"ff", uniswapFactory, keccak256(abi.encodePacked(token0, token1)), hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash ) ) ) ); } function calculateSushiPair(address token0, address token1) internal view returns (address pair) { pair = address( uint256( keccak256( abi.encodePacked( hex"ff", sushiswapFactory, keccak256(abi.encodePacked(token0, token1)), hex"e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303" // init code hash ) ) ) ); } // calculates the CREATE2 address for a pair without making any external calls function pairFor( address tokenA, address tokenB, bool sushi ) internal view returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = sushi ? calculateSushiPair(token0, token1) : calculateUniPair(token0, token1); } // calculates the CREATE2 address for a pair without making any external calls function pairFor(bytes32 tokenInfoA, bytes32 tokenInfoB) internal view returns (address pair) { (address tokenA, bool sushi) = tokenInfoA.unpack(); address tokenB = tokenInfoB.readToken(); (address token0, address token1) = sortTokens(tokenA, tokenB); pair = sushi ? calculateSushiPair(token0, token1) : calculateUniPair(token0, token1); } /** ========== Pair Reserves ========== */ // fetches and sorts the reserves for a pair function getReserves( bytes32 tokenInfoA, bytes32 tokenInfoB ) internal view returns (uint256 reserveA, uint256 reserveB) { (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pairFor(tokenInfoA, tokenInfoB)).getReserves(); (reserveA, reserveB) = tokenInfoA < tokenInfoB ? (reserve0, reserve1) : (reserve1, reserve0); } /** ========== Swap Amounts ========== */ // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountOut) { require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 numerator = reserveIn.mul(amountOut).mul(1000); uint256 denominator = reserveOut.sub(amountOut).mul(997); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut( bytes32[] memory path, uint256 amountIn ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); amounts = new uint[](path.length); amounts[0] = amountIn; for (uint i; i < path.length - 1; i++) { (uint reserveIn, uint reserveOut) = getReserves(path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn( bytes32[] memory path, uint256 amountOut ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "UniswapV2Library: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = getReserves(path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "./Narwhal.sol"; import "./libraries/TransferHelper.sol"; import "./interfaces/IUniswapV2Factory.sol"; import "./interfaces/IERC20.sol"; import "./interfaces/IWETH.sol"; contract NarwhalRouter is Narwhal { using TokenInfo for bytes32; using TokenInfo for address; using TransferHelper for address; using SafeMath for uint256; modifier ensure(uint256 deadline) { require(deadline >= block.timestamp, "NRouter: EXPIRED"); _; } constructor( address _uniswapFactory, address _sushiswapFactory, address _weth ) Narwhal(_uniswapFactory, _sushiswapFactory, _weth) {} function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, bytes32[] calldata path, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { amounts = getAmountsOut(path, amountIn); require(amounts[amounts.length - 1] >= amountOutMin, "NRouter: MIN_OUT"); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, bytes32[] calldata path, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { amounts = getAmountsIn(path, amountOut); require(amounts[0] <= amountInMax, "NRouter: MAX_IN"); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapExactETHForTokens( uint256 amountOutMin, bytes32[] calldata path, address to, uint256 deadline ) external payable ensure(deadline) returns (uint256[] memory amounts) { require(path[0].readToken() == address(weth), "NRouter: INVALID_PATH"); amounts = getAmountsOut(path, msg.value); require(amounts[amounts.length - 1] >= amountOutMin, "NRouter: MIN_OUT"); weth.deposit{value: amounts[0]}(); address(weth).safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, to); } function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, bytes32[] calldata path, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { require(path[path.length - 1].readToken() == address(weth), "NRouter: INVALID_PATH"); amounts = getAmountsIn(path, amountOut); require(amounts[0] <= amountInMax, "NRouter: MAX_IN"); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); weth.withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, bytes32[] calldata path, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { require(path[path.length - 1].readToken() == address(weth), "NRouter: INVALID_PATH"); amounts = getAmountsOut(path, amountIn); require(amounts[amounts.length - 1] >= amountOutMin, "NRouter: MIN_OUT"); path[0].readToken().safeTransferFrom( msg.sender, pairFor(path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); weth.withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapETHForExactTokens( uint256 amountOut, bytes32[] calldata path, address to, uint256 deadline ) external payable ensure(deadline) returns (uint256[] memory amounts) { require(path[0].readToken() == address(weth), "NRouter: INVALID_PATH"); amounts = getAmountsIn(path, amountOut); require(amounts[0] <= msg.value, "NRouter: MAX_IN"); weth.deposit{value: amounts[0]}(); address(weth).safeTransfer(pairFor(path[0], path[1]), amounts[0]); _swap(amounts, path, to); // // refund dust eth, if any if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; pragma experimental ABIEncoderV2; import "./IERC20.sol"; interface IIndexPool is IERC20 { /** * @dev Token record data structure * @param bound is token bound to pool * @param ready has token been initialized * @param lastDenormUpdate timestamp of last denorm change * @param denorm denormalized weight * @param desiredDenorm desired denormalized weight (used for incremental changes) * @param index index of address in tokens array * @param balance token balance */ struct Record { bool bound; bool ready; uint40 lastDenormUpdate; uint96 denorm; uint96 desiredDenorm; uint8 index; uint256 balance; } event LOG_SWAP( address indexed caller, address indexed tokenIn, address indexed tokenOut, uint256 tokenAmountIn, uint256 tokenAmountOut ); event LOG_JOIN( address indexed caller, address indexed tokenIn, uint256 tokenAmountIn ); event LOG_EXIT( address indexed caller, address indexed tokenOut, uint256 tokenAmountOut ); event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm); event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm); event LOG_TOKEN_REMOVED(address token); event LOG_TOKEN_ADDED( address indexed token, uint256 desiredDenorm, uint256 minimumBalance ); event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance); event LOG_TOKEN_READY(address indexed token); event LOG_PUBLIC_SWAP_ENABLED(); event LOG_MAX_TOKENS_UPDATED(uint256 maxPoolTokens); event LOG_SWAP_FEE_UPDATED(uint256 swapFee); function configure( address controller, string calldata name, string calldata symbol ) external; function initialize( address[] calldata tokens, uint256[] calldata balances, uint96[] calldata denorms, address tokenProvider, address unbindHandler, address exitFeeRecipient ) external; function setMaxPoolTokens(uint256 maxPoolTokens) external; function setSwapFee(uint256 swapFee) external; function delegateCompLikeToken(address token, address delegatee) external; function reweighTokens( address[] calldata tokens, uint96[] calldata desiredDenorms ) external; function reindexTokens( address[] calldata tokens, uint96[] calldata desiredDenorms, uint256[] calldata minimumBalances ) external; function setMinimumBalance(address token, uint256 minimumBalance) external; function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external; function joinswapExternAmountIn( address tokenIn, uint256 tokenAmountIn, uint256 minPoolAmountOut ) external returns (uint256/* poolAmountOut */); function joinswapPoolAmountOut( address tokenIn, uint256 poolAmountOut, uint256 maxAmountIn ) external returns (uint256/* tokenAmountIn */); function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external; function exitswapPoolAmountIn( address tokenOut, uint256 poolAmountIn, uint256 minAmountOut ) external returns (uint256/* tokenAmountOut */); function exitswapExternAmountOut( address tokenOut, uint256 tokenAmountOut, uint256 maxPoolAmountIn ) external returns (uint256/* poolAmountIn */); function gulp(address token) external; function flashBorrow( address recipient, address token, uint256 amount, bytes calldata data ) external; function swapExactAmountIn( address tokenIn, uint256 tokenAmountIn, address tokenOut, uint256 minAmountOut, uint256 maxPrice ) external returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */); function swapExactAmountOut( address tokenIn, uint256 maxAmountIn, address tokenOut, uint256 tokenAmountOut, uint256 maxPrice ) external returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */); function isPublicSwap() external view returns (bool); function getSwapFee() external view returns (uint256/* swapFee */); function getController() external view returns (address); function getMaxPoolTokens() external view returns (uint256); function isBound(address t) external view returns (bool); function getNumTokens() external view returns (uint256); function getCurrentTokens() external view returns (address[] memory tokens); function getCurrentDesiredTokens() external view returns (address[] memory tokens); function getDenormalizedWeight(address token) external view returns (uint256/* denorm */); function getTokenRecord(address token) external view returns (Record memory record); function extrapolatePoolValueFromToken() external view returns (address/* token */, uint256/* extrapolatedValue */); function getTotalDenormalizedWeight() external view returns (uint256); function getBalance(address token) external view returns (uint256); function getMinimumBalance(address token) external view returns (uint256); function getUsedBalance(address token) external view returns (uint256); function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function migrator() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; function setMigrator(address) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; library SafeMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function add(uint256 x, uint256 y, string memory errorMessage) internal pure returns (uint256 z) { require((z = x + y) >= x, errorMessage); } function sub(uint256 x, uint256 y, string memory errorMessage) internal pure returns (uint256 z) { require((z = x - y) <= x, errorMessage); } function mul(uint256 x, uint256 y, string memory errorMessage) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, errorMessage); } }
pragma solidity >=0.5.0; library TokenInfo { function unpack(bytes32 tokenInfo) internal pure returns (address token, bool useSushiNext) { assembly { token := shr(8, tokenInfo) useSushiNext := byte(31, tokenInfo) } } function pack(address token, bool sushi) internal pure returns (bytes32 tokenInfo) { assembly { tokenInfo := or( shl(8, token), sushi ) } } function readToken(bytes32 tokenInfo) internal pure returns (address token) { assembly { token := shr(8, tokenInfo) } } function readSushi(bytes32 tokenInfo) internal pure returns (bool useSushiNext) { assembly { useSushiNext := byte(31, tokenInfo) } } }
// SPDX-License-Identifier: MIT pragma solidity =0.7.6; /************************************************************************************************ Originally from https://github.com/Uniswap/uniswap-lib/blob/master/contracts/libraries/TransferHelper.sol This source code has been modified from the original, which was copied from the github repository at commit hash cfedb1f55864dcf8cc0831fdd8ec18eb045b7fd1. Subject to the MIT license *************************************************************************************************/ library TransferHelper { function safeApproveMax(address token, address to) internal { safeApprove(token, to, type(uint256).max); } function safeUnapprove(address token, address to) internal { safeApprove(token, to, 0); } function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes("approve(address,uint256)"))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TH:SA"); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes("transfer(address,uint256)"))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TH:ST"); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes("transferFrom(address,address,uint256)"))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TH:STF"); } function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(""); require(success, "TH:STE"); } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "none", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 800 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_uniswapFactory","type":"address"},{"internalType":"address","name":"_sushiswapFactory","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountInMax","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"uint256","name":"ethAmountOut","type":"uint256"}],"name":"burnAndSwapForExactETH","outputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountInMax","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"burnAndSwapForExactTokens","outputs":[{"internalType":"uint256","name":"poolAmountIn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"burnExactAndSwapForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"burnExactAndSwapForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"bytes32[]","name":"intermediaries","type":"bytes32[]"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"burnForAllTokensAndSwapForETH","outputs":[{"internalType":"uint256","name":"amountOutTotal","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"bytes32[]","name":"intermediaries","type":"bytes32[]"},{"internalType":"uint256","name":"poolAmountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"burnForAllTokensAndSwapForTokens","outputs":[{"internalType":"uint256","name":"amountOutTotal","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sushiswapFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"bytes32[]","name":"intermediaries","type":"bytes32[]"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"name":"swapETHForAllTokensAndMintExact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"name":"swapETHForTokensAndMintExact","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"}],"name":"swapExactETHForTokensAndMint","outputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"minPoolAmountOut","type":"uint256"}],"name":"swapExactTokensForTokensAndMint","outputs":[{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"bytes32[]","name":"intermediaries","type":"bytes32[]"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"}],"name":"swapTokensForAllTokensAndMintExact","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"bytes32[]","name":"path","type":"bytes32[]"},{"internalType":"address","name":"indexPool","type":"address"},{"internalType":"uint256","name":"poolAmountOut","type":"uint256"}],"name":"swapTokensForTokensAndMintExact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e06040523480156200001157600080fd5b5060405162004dfb38038062004dfb833981016040819052620000349162000079565b6001600160601b0319606093841b811660805291831b821660a05290911b1660c052620000c2565b80516001600160a01b03811681146200007457600080fd5b919050565b6000806000606084860312156200008e578283fd5b62000099846200005c565b9250620000a9602085016200005c565b9150620000b9604085016200005c565b90509250925092565b60805160601c60a05160601c60c05160601c614c8b620001706000398061017e5280610490528061069c52806107c852806108e45280610a185280610ae85280610bf15280610d1d5280610df75280610f4f52806110045280611461528061150352806116535280611698528061171552806117ca528061186352806119395280611be75280611d5d5280611e665250806111cc5280613e045250806116295280613d275250614c8b6000f3fe60806040526004361061016e5760003560e01c8063501070be116100cb57806390ab67311161007f578063b96e9f3311610059578063b96e9f33146103ba578063beb586ae146103da578063e9040a97146103fa576101a7565b806390ab673114610367578063a86952b414610387578063b079cb8c1461039a576101a7565b806367e34f97116100b057806367e34f971461031f5780638bdb2afa146103325780638f32871e14610347576101a7565b8063501070be146102ea57806365526631146102ff576101a7565b80633ddb70281161012257806343405d511161010757806343405d511461028a5780634e4665e9146102aa5780634f553b26146102ca576101a7565b80633ddb7028146102555780633fc8cef314610268576101a7565b8063108a6d6b11610153578063108a6d6b146102025780632064bcbd146102155780633c3db8c114610235576101a7565b80630c05f882146101ac5780630c288791146101e2576101a7565b366101a757336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101a557fe5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004614536565b61041a565b6040516101d99190614b22565b60405180910390f35b3480156101ee57600080fd5b506101cc6101fd36600461466b565b61043a565b6101cc610210366004614462565b610488565b34801561022157600080fd5b506101cc61023036600461466b565b610853565b610248610243366004614892565b610897565b6040516101d991906149c2565b610248610263366004614892565b610ba4565b34801561027457600080fd5b5061027d610df5565b6040516101d9919061498d565b34801561029657600080fd5b506101cc6102a5366004614892565b610e19565b3480156102b657600080fd5b506101cc6102c536600461466b565b610f43565b3480156102d657600080fd5b506102486102e53660046148f7565b611075565b3480156102f657600080fd5b5061027d6111ca565b34801561030b57600080fd5b506101cc61031a3660046144bc565b6111ee565b6101cc61032d36600461477a565b61145d565b34801561033e57600080fd5b5061027d611627565b34801561035357600080fd5b506101cc6103623660046145dc565b61164b565b34801561037357600080fd5b506101cc61038236600461466b565b611709565b6101a561039536600461477a565b61183b565b3480156103a657600080fd5b506101a56103b5366004614892565b611a54565b3480156103c657600080fd5b506102486103d53660046148f7565b611b92565b3480156103e657600080fd5b506102486103f53660046148f7565b611e11565b34801561040657600080fd5b506102486104153660046148f7565b611f8b565b600061042d89848a8a8a8a8a8933612071565b9998505050505050505050565b600061047e86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503391506122329050565b9695505050505050565b6000803490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156104e957600080fd5b505af11580156104fd573d6000803e3d6000fd5b50505050506000866001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561053d57600080fd5b505afa158015610551573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261057991908101906146cd565b805190915085146105a55760405162461bcd60e51b815260040161059c90614aeb565b60405180910390fd5b6000815167ffffffffffffffff811180156105bf57600080fd5b506040519080825280602002602001820160405280156105e9578160200160208202803683370190505b5090506000610668868a6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561062b57600080fd5b505afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610663919061487a565b612394565b6040805160038082526080820190925291925060009190602082016060803683370190505090506106c36001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660006124ba565b816000815181106106d057fe5b60200260200101818152505060005b845181101561073f5761071b8b8b8b848181106106f857fe5b9050602002013587848151811061070b57fe5b602002602001015185878b6124c4565b85838151811061072757fe5b602090810291909101019190915295506001016106df565b506040516313da703560e21b81526001600160a01b038b1690634f69c0d49061076e908a908790600401614b85565b600060405180830381600087803b15801561078857600080fd5b505af115801561079c573d6000803e3d6000fd5b505050506107ab8a338961275b565b841561083957604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906107fd908890600401614b22565b600060405180830381600087803b15801561081757600080fd5b505af115801561082b573d6000803e3d6000fd5b5050505061083933866128c4565b610843348661296f565b955050505050505b949350505050565b600061047e86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503391506129c79050565b606081428110156108e2576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109288787600081811061091c57fe5b90506020020135612b01565b6001600160a01b03161461097b576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b6109b98686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9250612b07915050565b915034826000815181106109c957fe5b60200260200101511115610a16576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110610a5257fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b5050505050610b1f610ad187876000818110610ab157fe5b9050602002013588886001818110610ac557fe5b90506020020135612c52565b83600081518110610ade57fe5b60200260200101517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661275b9092919063ffffffff16565b610b5e82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b81600081518110610b6b57fe5b6020026020010151341115610b9a57610b9a3383600081518110610b8b57fe5b602002602001015134036128c4565b5095945050505050565b60608142811015610bef576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610c298787600081811061091c57fe5b6001600160a01b031614610c7c576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b610cba868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250349250612e72915050565b91508682600184510381518110610ccd57fe5b60200260200101511015610d1b576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110610d5757fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d8a57600080fd5b505af1158015610d9e573d6000803e3d6000fd5b5050505050610db6610ad187876000818110610ab157fe5b610b9a82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080610e5a8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9250612e72915050565b9050610eba33610e8488886000818110610e7057fe5b9050602002013589896001818110610ac557fe5b83600081518110610e9157fe5b6020026020010151610ea98a8a600081811061091c57fe5b6001600160a01b0316929190612fa8565b610ef981878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b600081600183510381518110610f0b57fe5b60200260200101519050610f35610f2d888860018b8b90500381811061091c57fe5b82878761311a565b925050505b95945050505050565b60006001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610f828585600019810181811061091c57fe5b6001600160a01b031614610fa85760405162461bcd60e51b815260040161059c90614a0c565b610fea86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503091506122329050565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90611039908590600401614b22565b600060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b50505050610f3a33836128c4565b606081428110156110c0576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6110fe8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612e72915050565b9150868260018451038151811061111157fe5b6020026020010151101561115f576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b6111803361117388886000818110610e7057fe5b84600081518110610e9157fe5b6111bf82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b509695505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000808290506000886001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561122f57600080fd5b505afa158015611243573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261126b91908101906146cd565b8051909150871461128e5760405162461bcd60e51b815260040161059c90614aeb565b6112a36001600160a01b038616333087612fa8565b6000815167ffffffffffffffff811180156112bd57600080fd5b506040519080825280602002602001820160405280156112e7578160200160208202803683370190505b5090506000611329888c6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561062b57600080fd5b6040805160038082526080820190925291925060009190602082016060803683370190505090506113646001600160a01b03891660006124ba565b8160008151811061137157fe5b60200260200101818152505060005b84518110156113bd576113998d8d8d848181106106f857fe5b8583815181106113a557fe5b60209081029190910101919091529550600101611380565b506040516313da703560e21b81526001600160a01b038d1690634f69c0d4906113ec908c908790600401614b85565b600060405180830381600087803b15801561140657600080fd5b505af115801561141a573d6000803e3d6000fd5b505050506114298c338b61275b565b8415611443576114436001600160a01b038916338761275b565b61144d878661296f565b9c9b505050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166114998686600081811061091c57fe5b6001600160a01b0316146114bf5760405162461bcd60e51b815260040161059c90614a0c565b60006114ff868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250349250612e72915050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08260008151811061153d57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561157057600080fd5b505af1158015611584573d6000803e3d6000fd5b50505050506115a961159c87876000818110610ab157fe5b82600081518110610ade57fe5b6115e881878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b6000816001835103815181106115fa57fe5b6020026020010151905061161c610f2d888860018b8b90500381811061091c57fe5b979650505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061167e887f000000000000000000000000000000000000000000000000000000000000000089898989898930612071565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906116cd908490600401614b22565b600060405180830381600087803b1580156116e757600080fd5b505af11580156116fb573d6000803e3d6000fd5b5050505061161c33826128c4565b60006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166117488585600019810181811061091c57fe5b6001600160a01b03161461176e5760405162461bcd60e51b815260040161059c90614a0c565b6117b086868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503091506129c79050565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906117ff908490600401614b22565b600060405180830381600087803b15801561181957600080fd5b505af115801561182d573d6000803e3d6000fd5b50505050610f3a33826128c4565b60006118508585600019810181811061091c57fe5b9050600061185f8483856131b6565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661189b8787600081811061091c57fe5b6001600160a01b0316146118c15760405162461bcd60e51b815260040161059c906149d5565b6000611901878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612b07915050565b9050348160008151811061191157fe5b602002602001015111156119375760405162461bcd60e51b815260040161059c90614a3b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08260008151811061197357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156119a657600080fd5b505af11580156119ba573d6000803e3d6000fd5b50505050506119d261159c88886000818110610e7057fe5b611a1181888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b80600081518110611a1e57fe5b6020026020010151341115611a3e57611a3e3382600081518110610b8b57fe5b611a4a838387876134a4565b5050505b50505050565b6000611a698585600019810181811061091c57fe5b90506000611a788483856131b6565b90506000611aba878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612b07915050565b90508781600081518110611aca57fe5b60200260200101511115611af05760405162461bcd60e51b815260040161059c90614a3b565b611b3d33611b1889896000818110611b0457fe5b905060200201358a8a6001818110610ac557fe5b83600081518110611b2557fe5b6020026020010151610ea98b8b600081811061091c57fe5b611b7c81888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b611b88838387876134a4565b5050505050505050565b60608142811015611bdd576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611c1a8787600019810181811061091c57fe5b6001600160a01b031614611c6d576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b611cab8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612b07915050565b91508682600081518110611cbb57fe5b60200260200101511115611d08576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b611d1c3361117388886000818110610e7057fe5b611d5b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185510381518110611d9a57fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611dd857600080fd5b505af1158015611dec573d6000803e3d6000fd5b505050506111bf8483600185510381518110611e0457fe5b60200260200101516128c4565b60608142811015611e5c576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611e998787600019810181811061091c57fe5b6001600160a01b031614611eec576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b611f2a8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612e72915050565b91508682600184510381518110611f3d57fe5b60200260200101511015611d08576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b60608142811015611fd6576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6120148686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612b07915050565b9150868260008151811061202457fe5b6020026020010151111561115f576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b600061207f8a333087612fa8565b60008a6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b1580156120ba57600080fd5b505afa1580156120ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f691908101906146cd565b8051909150861480156121095750805188145b6121255760405162461bcd60e51b815260040161059c90614a64565b60405163b02f0b7360e01b81526001600160a01b038c169063b02f0b73906121559088908d908d90600401614b2b565b600060405180830381600087803b15801561216f57600080fd5b505af1158015612183573d6000803e3d6000fd5b5050604080516003808252608082019092526000935091506020820160608036833701905050905060005b82518110156122025760006121eb8483815181106121c857fe5b60200260200101518b8b858181106121dc57fe5b905060200201358f868a61353d565b90506121f7858261373f565b9450506001016121ae565b50848310156122235760405162461bcd60e51b815260040161059c90614ac1565b50509998505050505050505050565b60006122496001600160a01b038716333088612fa8565b60006122558585612b07565b9050866001600160a01b03166302c967486122838760008151811061227657fe5b6020026020010151612b01565b8360008151811061229057fe5b6020026020010151896040518463ffffffff1660e01b81526004016122b7939291906149a1565b602060405180830381600087803b1580156122d157600080fd5b505af11580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612309919061487a565b915061236a61231e8660008151811061227657fe5b6123508760008151811061232e57fe5b60200260200101518860018151811061234357fe5b6020026020010151612c52565b8360008151811061235d57fe5b602002602001015161275b565b612375818685612cac565b610b9a33612383888561296f565b6001600160a01b038a16919061275b565b6000816123e8576040805162461bcd60e51b815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806124105750670de0b6b3a764000084828161240d57fe5b04145b612454576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b600283048101818110156124a2576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b60008482816124ad57fe5b0493505050505b92915050565b60089190911b1790565b60008060006124d98660008151811061227657fe5b90506000896001600160a01b0316634aa4e0b5896040518263ffffffff1660e01b8152600401612509919061498d565b60206040518083038186803b15801561252157600080fd5b505afa158015612535573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612559919061487a565b90506125658682613797565b9350876001600160a01b0316826001600160a01b031614156125bb5760408051808201909152600f81526e272937baba32b91d1026a0ac2fa4a760891b60208201526125b49086908690613859565b925061273a565b74ffffffffffffffffffffffffffffffffffffffffff89169860a81c6125ea6001600160a01b038416826124ba565b886000815181106125f757fe5b60209081029190910101528961263d576002885261261f6001600160a01b038a1660006124ba565b8860018151811061262c57fe5b602002602001018181525050612676565b60038852604088018a905261265c6001600160a01b038a1660006124ba565b8860028151811061266957fe5b6020026020010181815250505b60006126828987612b07565b90506126d48160008151811061269457fe5b60200260200101516040518060400160405280600f81526020016e272937baba32b91d1026a0ac2fa4a760891b815250896138599092919063ffffffff16565b945061272c6126fe8a6000815181106126e957fe5b60200260200101518b60018151811061234357fe5b8260008151811061270b57fe5b6020026020010151866001600160a01b031661275b9092919063ffffffff16565b612737818a30612cac565b50505b61274e6001600160a01b0389168b866138f1565b5050965096945050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b602083106127d75780518252601f1990920191602091820191016127b8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612839576040519150601f19603f3d011682016040523d82523d6000602084013e61283e565b606091505b509150915081801561286c57508051158061286c575080806020019051602081101561286957600080fd5b50515b6128bd576040805162461bcd60e51b815260206004820152600560248201527f54483a5354000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b6040516000906001600160a01b0384169083908381818185875af1925050503d806000811461290f576040519150601f19603f3d011682016040523d82523d6000602084013e612914565b606091505b505090508061296a576040805162461bcd60e51b815260206004820152600660248201527f54483a5354450000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050565b808203828111156124b4576040805162461bcd60e51b815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b60006129d586333088612fa8565b6000866001600160a01b03166346ab38f16129f68760008151811061227657fe5b8860006040518463ffffffff1660e01b8152600401612a17939291906149a1565b602060405180830381600087803b158015612a3157600080fd5b505af1158015612a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a69919061487a565b90506000612a778683612e72565b905080600182510381518110612a8957fe5b6020026020010151925084831015612ab35760405162461bcd60e51b815260040161059c90614ac1565b612aeb612ac68760008151811061227657fe5b61235088600081518110612ad657fe5b60200260200101518960018151811061234357fe5b612af6818786612cac565b505095945050505050565b60081c90565b6060600283511015612b60576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b825167ffffffffffffffff81118015612b7857600080fd5b50604051908082528060200260200182016040528015612ba2578160200160208202803683370190505b5090508181600183510381518110612bb657fe5b60209081029190910101528251600019015b8015612c4b57600080612c04866001850381518110612be357fe5b6020026020010151878581518110612bf757fe5b6020026020010151613a53565b91509150612c26848481518110612c1757fe5b60200260200101518383613b03565b846001850381518110612c3557fe5b6020908102919091010152505060001901612bc8565b5092915050565b6000806000612c6085613bd1565b915091506000612c6f85612b01565b9050600080612c7e8584613bdf565b9150915083612c9657612c918282613cbd565b612ca0565b612ca08282613d9a565b98975050505050505050565b60005b6001835103811015611a4e57600080848381518110612cca57fe5b6020026020010151858460010181518110612ce157fe5b6020026020010151915091506000868460010181518110612cfe57fe5b60200260200101519050600080838510612d1a57826000612d1e565b6000835b91509150600060028951038710612d355787612d48565b612d48858a896002018151811061234357fe5b9050612d548686612c52565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015612d91576020820181803683370190505b506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612df9578181015183820152602001612de1565b50505050905090810190601f168015612e265780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015612e4857600080fd5b505af1158015612e5c573d6000803e3d6000fd5b505060019098019750612caf9650505050505050565b6060600283511015612ecb576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b825167ffffffffffffffff81118015612ee357600080fd5b50604051908082528060200260200182016040528015612f0d578160200160208202803683370190505b5090508181600081518110612f1e57fe5b60200260200101818152505060005b6001845103811015612c4b57600080612f62868481518110612f4b57fe5b6020026020010151878560010181518110612bf757fe5b91509150612f84848481518110612f7557fe5b60200260200101518383613e77565b848460010181518110612f9357fe5b60209081029190910101525050600101612f2d565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b6020831061302c5780518252601f19909201916020918201910161300d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461308e576040519150601f19603f3d011682016040523d82523d6000602084013e613093565b606091505b50915091508180156130c15750805115806130c157508080602001905160208110156130be57600080fd5b50515b613112576040805162461bcd60e51b815260206004820152600660248201527f54483a5354460000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050505050565b60006131278584866138f1565b604051635db3427760e01b81526001600160a01b03841690635db3427790613157908890889087906004016149a1565b602060405180830381600087803b15801561317157600080fd5b505af1158015613185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a9919061487a565b905061084b83338361275b565b600080846001600160a01b03166364c7d661856040518263ffffffff1660e01b81526004016131e5919061498d565b60e06040518083038186803b1580156131fd57600080fd5b505afa158015613211573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323591906147d5565b90508060200151613321576040516391bfa2bf60e01b81526000906001600160a01b038716906391bfa2bf9061326f90889060040161498d565b60206040518083038186803b15801561328757600080fd5b505afa15801561329b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132bf919061487a565b905060006132da6132d4838560c00151613f4f565b83612394565b905060006132ef6658d15e1762800083613797565b60c08501849052905061330a6703782dace9d9000082613fb5565b6bffffffffffffffffffffffff1660608501525050505b6000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561335c57600080fd5b505afa158015613370573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613394919061487a565b90506000866001600160a01b031663936c34776040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d157600080fd5b505afa1580156133e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613409919061487a565b90506000876001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b15801561344657600080fd5b505afa15801561345a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347e919061487a565b9050612ca08460c0015185606001516bffffffffffffffffffffffff1685858a86614016565b6134af8483856138f1565b60405163036836fd60e51b81526001600160a01b03831690636d06dfa0906134df908790859088906004016149a1565b602060405180830381600087803b1580156134f957600080fd5b505af115801561350d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613531919061487a565b50611a4e82338361275b565b600080866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161356c919061498d565b60206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc919061487a565b9050846001600160a01b0316876001600160a01b03161415613604579050806001600160a01b03831630146135ff576135ff6001600160a01b038816848361275b565b610b9a565b74ffffffffffffffffffffffffffffffffffffffffff86169560a81c6136336001600160a01b038916826124ba565b8560008151811061364057fe5b60209081029190910101528661368657600285526136686001600160a01b03871660006124ba565b8560018151811061367557fe5b6020026020010181815250506136bf565b60038552604085018790526136a56001600160a01b03871660006124ba565b856002815181106136b257fe5b6020026020010181815250505b60006136cb8684612e72565b905061370e6136e08760008151811061232e57fe5b826000815181106136ed57fe5b60200260200101518b6001600160a01b031661275b9092919063ffffffff16565b613719818787612cac565b8060018251038151811061372957fe5b6020026020010151935050505095945050505050565b808201828110156124b4576040805162461bcd60e51b815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008282028315806137b15750828482816137ae57fe5b04145b6137f5576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6706f05b59d3b20000810181811015613848576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6000670de0b6b3a7640000826124ad565b81830381848211156138e95760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156138ae578181015183820152602001613896565b50505050905090810190601f1680156138db5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1781529251825160009485949389169392918291908083835b6020831061396d5780518252601f19909201916020918201910161394e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146139cf576040519150601f19603f3d011682016040523d82523d6000602084013e6139d4565b606091505b5091509150818015613a02575080511580613a0257508080602001905160208110156139ff57600080fd5b50515b6128bd576040805162461bcd60e51b815260206004820152600560248201527f54483a5341000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600080600080613a638686612c52565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613a9b57600080fd5b505afa158015613aaf573d6000803e3d6000fd5b505050506040513d6060811015613ac557600080fd5b5080516020909101516dffffffffffffffffffffffffffff9182169350169050848610613af3578082613af6565b81815b9097909650945050505050565b6000808411613b435760405162461bcd60e51b815260040180806020018281038252602c815260200180614bdb602c913960400191505060405180910390fd5b600083118015613b535750600082115b613b8e5760405162461bcd60e51b8152600401808060200182810382526028815260200180614c2c6028913960400191505060405180910390fd5b6000613ba66103e8613ba086886140c9565b906140c9565b90506000613bba6103e5613ba0868961296f565b905061047e6001828481613bca57fe5b049061373f565b600881901c9160ff90911690565b600080826001600160a01b0316846001600160a01b03161415613c335760405162461bcd60e51b8152600401808060200182810382526025815260200180614c076025913960400191505060405180910390fd5b826001600160a01b0316846001600160a01b031610613c53578284613c56565b83835b90925090506001600160a01b038216613cb6576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401527f000000000000000000000000000000000000000000000000000000000000000090951b166069820152607d8101939093527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808501919091528151808503909101815260bd9093019052815191012090565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401527f000000000000000000000000000000000000000000000000000000000000000090951b166069820152607d8101939093527fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303609d808501919091528151808503909101815260bd9093019052815191012090565b6000808411613eb75760405162461bcd60e51b815260040180806020018281038252602b815260200180614c54602b913960400191505060405180910390fd5b600083118015613ec75750600082115b613f025760405162461bcd60e51b8152600401808060200182810382526028815260200180614c2c6028913960400191505060405180910390fd5b6000613f10856103e56140c9565b90506000613f1e82856140c9565b90506000613f3883613f32886103e86140c9565b9061373f565b9050808281613f4357fe5b04979650505050505050565b6000806000613f5e8585614135565b9150915080156138e9576040805162461bcd60e51b815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b60008282018381101561400f576040805162461bcd60e51b815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b6000806140238786612394565b905060006140318786613fb5565b9050600061403f8289612394565b90506000614055670de0b6b3a764000085612394565b905060006140638383614157565b90506000614071828e613797565b9050600061407f828f613f4f565b9050600061409e614098670de0b6b3a76400008a613f4f565b8b613797565b90506140b682610663670de0b6b3a764000084613f4f565b9f9e505050505050505050505050505050565b60008115806140e4575050808202828282816140e157fe5b04145b6124b4576040805162461bcd60e51b815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008082841061414b5750508082036000613cb6565b50508181036001613cb6565b600060018310156141af576040805162461bcd60e51b815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff83111561420c576040805162461bcd60e51b815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b600061421783614269565b905060006142258483613f4f565b9050600061423b8661423685614286565b614294565b90508161424c5792506124b4915050565b600061425d87846305f5e1006142eb565b905061161c8282613797565b6000670de0b6b3a764000061427d83614286565b0290505b919050565b670de0b6b3a7640000900490565b600080600283066142ad57670de0b6b3a76400006142af565b835b90506002830492505b821561400f576142c88485613797565b935060028306156142e0576142dd8185613797565b90505b6002830492506142b8565b600082818061430287670de0b6b3a7640000614135565b9092509050670de0b6b3a764000080600060015b8884106143bf576000670de0b6b3a76400008202905060008061434a8a61434585670de0b6b3a7640000613f4f565b614135565b915091506143618761435c848c613797565b613797565b965061436d8784612394565b96508661437c575050506143bf565b8715614386579315935b8015614390579315935b84156143a7576143a08688613f4f565b95506143b4565b6143b18688613fb5565b95505b505050600101614316565b50909998505050505050505050565b60008083601f8401126143df578182fd5b50813567ffffffffffffffff8111156143f6578182fd5b6020830191508360208083028501011115613cb657600080fd5b8051801515811461428157600080fd5b805164ffffffffff8116811461428157600080fd5b805160ff8116811461428157600080fd5b80516bffffffffffffffffffffffff8116811461428157600080fd5b60008060008060608587031215614477578384fd5b843561448281614bc2565b9350602085013567ffffffffffffffff81111561449d578384fd5b6144a9878288016143ce565b9598909750949560400135949350505050565b60008060008060008060a087890312156144d4578182fd5b86356144df81614bc2565b9550602087013567ffffffffffffffff8111156144fa578283fd5b61450689828a016143ce565b90965094505060408701359250606087013561452181614bc2565b80925050608087013590509295509295509295565b60008060008060008060008060c0898b031215614551578182fd5b883561455c81614bc2565b9750602089013567ffffffffffffffff80821115614578578384fd5b6145848c838d016143ce565b909950975060408b013591508082111561459c578384fd5b506145a98b828c016143ce565b9096509450506060890135925060808901356145c481614bc2565b8092505060a089013590509295985092959890939650565b600080600080600080600060a0888a0312156145f6578283fd5b873561460181614bc2565b9650602088013567ffffffffffffffff8082111561461d578485fd5b6146298b838c016143ce565b909850965060408a0135915080821115614641578485fd5b5061464e8a828b016143ce565b989b979a5095989597966060870135966080013595509350505050565b600080600080600060808688031215614682578081fd5b853561468d81614bc2565b945060208601359350604086013567ffffffffffffffff8111156146af578182fd5b6146bb888289016143ce565b96999598509660600135949350505050565b600060208083850312156146df578182fd5b825167ffffffffffffffff808211156146f6578384fd5b818501915085601f830112614709578384fd5b81518181111561471557fe5b8381029150614725848301614b9e565b8181528481019084860184860187018a101561473f578788fd5b8795505b8386101561476d578051945061475885614bc2565b84835260019590950194918601918601614743565b5098975050505050505050565b6000806000806060858703121561478f578182fd5b843567ffffffffffffffff8111156147a5578283fd5b6147b1878288016143ce565b90955093505060208501356147c581614bc2565b9396929550929360400135925050565b600060e082840312156147e6578081fd5b60405160e0810181811067ffffffffffffffff8211171561480357fe5b60405261480f83614410565b815261481d60208401614410565b602082015261482e60408401614420565b604082015261483f60608401614446565b606082015261485060808401614446565b608082015261486160a08401614435565b60a082015260c083015160c08201528091505092915050565b60006020828403121561488b578081fd5b5051919050565b6000806000806000608086880312156148a9578283fd5b85359450602086013567ffffffffffffffff8111156148c6578384fd5b6148d2888289016143ce565b90955093505060408601356148e681614bc2565b949793965091946060013592915050565b60008060008060008060a0878903121561490f578384fd5b8635955060208701359450604087013567ffffffffffffffff811115614933578485fd5b61493f89828a016143ce565b909550935050606087013561452181614bc2565b6000815180845260208085019450808401835b8381101561498257815187529582019590820190600101614966565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020825261400f6020830184614953565b6020808252600c908201527f494e56414c49445f504154480000000000000000000000000000000000000000604082015260600190565b60208082526015908201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604082015260600190565b6020808252600f908201526e272937baba32b91d1026a0ac2fa4a760891b604082015260600190565b6020808252602c908201527f496e6465786564556e6973776170526f757465724275726e65723a204241445f60408201527f41525241595f4c454e4754480000000000000000000000000000000000000000606082015260800190565b60208082526010908201526f13949bdd5d195c8e8813525397d3d55560821b604082015260600190565b60208082526010908201527f4e526f757465723a204152525f4c454e00000000000000000000000000000000604082015260600190565b90815260200190565b6000848252604060208301528260408301527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614b69578081fd5b6020830280856060850137919091016060019081529392505050565b60008382526040602083015261084b6040830184614953565b60405181810167ffffffffffffffff81118282101715614bba57fe5b604052919050565b6001600160a01b0381168114614bd757600080fd5b5056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a164736f6c6343000706000a0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x60806040526004361061016e5760003560e01c8063501070be116100cb57806390ab67311161007f578063b96e9f3311610059578063b96e9f33146103ba578063beb586ae146103da578063e9040a97146103fa576101a7565b806390ab673114610367578063a86952b414610387578063b079cb8c1461039a576101a7565b806367e34f97116100b057806367e34f971461031f5780638bdb2afa146103325780638f32871e14610347576101a7565b8063501070be146102ea57806365526631146102ff576101a7565b80633ddb70281161012257806343405d511161010757806343405d511461028a5780634e4665e9146102aa5780634f553b26146102ca576101a7565b80633ddb7028146102555780633fc8cef314610268576101a7565b8063108a6d6b11610153578063108a6d6b146102025780632064bcbd146102155780633c3db8c114610235576101a7565b80630c05f882146101ac5780630c288791146101e2576101a7565b366101a757336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101a557fe5b005b600080fd5b3480156101b857600080fd5b506101cc6101c7366004614536565b61041a565b6040516101d99190614b22565b60405180910390f35b3480156101ee57600080fd5b506101cc6101fd36600461466b565b61043a565b6101cc610210366004614462565b610488565b34801561022157600080fd5b506101cc61023036600461466b565b610853565b610248610243366004614892565b610897565b6040516101d991906149c2565b610248610263366004614892565b610ba4565b34801561027457600080fd5b5061027d610df5565b6040516101d9919061498d565b34801561029657600080fd5b506101cc6102a5366004614892565b610e19565b3480156102b657600080fd5b506101cc6102c536600461466b565b610f43565b3480156102d657600080fd5b506102486102e53660046148f7565b611075565b3480156102f657600080fd5b5061027d6111ca565b34801561030b57600080fd5b506101cc61031a3660046144bc565b6111ee565b6101cc61032d36600461477a565b61145d565b34801561033e57600080fd5b5061027d611627565b34801561035357600080fd5b506101cc6103623660046145dc565b61164b565b34801561037357600080fd5b506101cc61038236600461466b565b611709565b6101a561039536600461477a565b61183b565b3480156103a657600080fd5b506101a56103b5366004614892565b611a54565b3480156103c657600080fd5b506102486103d53660046148f7565b611b92565b3480156103e657600080fd5b506102486103f53660046148f7565b611e11565b34801561040657600080fd5b506102486104153660046148f7565b611f8b565b600061042d89848a8a8a8a8a8933612071565b9998505050505050505050565b600061047e86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503391506122329050565b9695505050505050565b6000803490507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156104e957600080fd5b505af11580156104fd573d6000803e3d6000fd5b50505050506000866001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561053d57600080fd5b505afa158015610551573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261057991908101906146cd565b805190915085146105a55760405162461bcd60e51b815260040161059c90614aeb565b60405180910390fd5b6000815167ffffffffffffffff811180156105bf57600080fd5b506040519080825280602002602001820160405280156105e9578160200160208202803683370190505b5090506000610668868a6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561062b57600080fd5b505afa15801561063f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610663919061487a565b612394565b6040805160038082526080820190925291925060009190602082016060803683370190505090506106c36001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660006124ba565b816000815181106106d057fe5b60200260200101818152505060005b845181101561073f5761071b8b8b8b848181106106f857fe5b9050602002013587848151811061070b57fe5b602002602001015185878b6124c4565b85838151811061072757fe5b602090810291909101019190915295506001016106df565b506040516313da703560e21b81526001600160a01b038b1690634f69c0d49061076e908a908790600401614b85565b600060405180830381600087803b15801561078857600080fd5b505af115801561079c573d6000803e3d6000fd5b505050506107ab8a338961275b565b841561083957604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906107fd908890600401614b22565b600060405180830381600087803b15801561081757600080fd5b505af115801561082b573d6000803e3d6000fd5b5050505061083933866128c4565b610843348661296f565b955050505050505b949350505050565b600061047e86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503391506129c79050565b606081428110156108e2576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166109288787600081811061091c57fe5b90506020020135612b01565b6001600160a01b03161461097b576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b6109b98686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9250612b07915050565b915034826000815181106109c957fe5b60200260200101511115610a16576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db083600081518110610a5257fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b5050505050610b1f610ad187876000818110610ab157fe5b9050602002013588886001818110610ac557fe5b90506020020135612c52565b83600081518110610ade57fe5b60200260200101517f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031661275b9092919063ffffffff16565b610b5e82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b81600081518110610b6b57fe5b6020026020010151341115610b9a57610b9a3383600081518110610b8b57fe5b602002602001015134036128c4565b5095945050505050565b60608142811015610bef576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316610c298787600081811061091c57fe5b6001600160a01b031614610c7c576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b610cba868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250349250612e72915050565b91508682600184510381518110610ccd57fe5b60200260200101511015610d1b576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db083600081518110610d5757fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d8a57600080fd5b505af1158015610d9e573d6000803e3d6000fd5b5050505050610db6610ad187876000818110610ab157fe5b610b9a82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b600080610e5a8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9250612e72915050565b9050610eba33610e8488886000818110610e7057fe5b9050602002013589896001818110610ac557fe5b83600081518110610e9157fe5b6020026020010151610ea98a8a600081811061091c57fe5b6001600160a01b0316929190612fa8565b610ef981878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b600081600183510381518110610f0b57fe5b60200260200101519050610f35610f2d888860018b8b90500381811061091c57fe5b82878761311a565b925050505b95945050505050565b60006001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216610f828585600019810181811061091c57fe5b6001600160a01b031614610fa85760405162461bcd60e51b815260040161059c90614a0c565b610fea86868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503091506122329050565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d90611039908590600401614b22565b600060405180830381600087803b15801561105357600080fd5b505af1158015611067573d6000803e3d6000fd5b50505050610f3a33836128c4565b606081428110156110c0576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6110fe8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612e72915050565b9150868260018451038151811061111157fe5b6020026020010151101561115f576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b6111803361117388886000818110610e7057fe5b84600081518110610e9157fe5b6111bf82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250899250612cac915050565b509695505050505050565b7f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac81565b6000808290506000886001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b15801561122f57600080fd5b505afa158015611243573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261126b91908101906146cd565b8051909150871461128e5760405162461bcd60e51b815260040161059c90614aeb565b6112a36001600160a01b038616333087612fa8565b6000815167ffffffffffffffff811180156112bd57600080fd5b506040519080825280602002602001820160405280156112e7578160200160208202803683370190505b5090506000611329888c6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561062b57600080fd5b6040805160038082526080820190925291925060009190602082016060803683370190505090506113646001600160a01b03891660006124ba565b8160008151811061137157fe5b60200260200101818152505060005b84518110156113bd576113998d8d8d848181106106f857fe5b8583815181106113a557fe5b60209081029190910101919091529550600101611380565b506040516313da703560e21b81526001600160a01b038d1690634f69c0d4906113ec908c908790600401614b85565b600060405180830381600087803b15801561140657600080fd5b505af115801561141a573d6000803e3d6000fd5b505050506114298c338b61275b565b8415611443576114436001600160a01b038916338761275b565b61144d878661296f565b9c9b505050505050505050505050565b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166114998686600081811061091c57fe5b6001600160a01b0316146114bf5760405162461bcd60e51b815260040161059c90614a0c565b60006114ff868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250349250612e72915050565b90507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08260008151811061153d57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561157057600080fd5b505af1158015611584573d6000803e3d6000fd5b50505050506115a961159c87876000818110610ab157fe5b82600081518110610ade57fe5b6115e881878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b6000816001835103815181106115fa57fe5b6020026020010151905061161c610f2d888860018b8b90500381811061091c57fe5b979650505050505050565b7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b600061167e887f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc289898989898930612071565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906116cd908490600401614b22565b600060405180830381600087803b1580156116e757600080fd5b505af11580156116fb573d6000803e3d6000fd5b5050505061161c33826128c4565b60006001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166117488585600019810181811061091c57fe5b6001600160a01b03161461176e5760405162461bcd60e51b815260040161059c90614a0c565b6117b086868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508892503091506129c79050565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906117ff908490600401614b22565b600060405180830381600087803b15801561181957600080fd5b505af115801561182d573d6000803e3d6000fd5b50505050610f3a33826128c4565b60006118508585600019810181811061091c57fe5b9050600061185f8483856131b6565b90507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031661189b8787600081811061091c57fe5b6001600160a01b0316146118c15760405162461bcd60e51b815260040161059c906149d5565b6000611901878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612b07915050565b9050348160008151811061191157fe5b602002602001015111156119375760405162461bcd60e51b815260040161059c90614a3b565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db08260008151811061197357fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156119a657600080fd5b505af11580156119ba573d6000803e3d6000fd5b50505050506119d261159c88886000818110610e7057fe5b611a1181888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b80600081518110611a1e57fe5b6020026020010151341115611a3e57611a3e3382600081518110610b8b57fe5b611a4a838387876134a4565b5050505b50505050565b6000611a698585600019810181811061091c57fe5b90506000611a788483856131b6565b90506000611aba878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250869250612b07915050565b90508781600081518110611aca57fe5b60200260200101511115611af05760405162461bcd60e51b815260040161059c90614a3b565b611b3d33611b1889896000818110611b0457fe5b905060200201358a8a6001818110610ac557fe5b83600081518110611b2557fe5b6020026020010151610ea98b8b600081811061091c57fe5b611b7c81888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b611b88838387876134a4565b5050505050505050565b60608142811015611bdd576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216611c1a8787600019810181811061091c57fe5b6001600160a01b031614611c6d576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b611cab8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612b07915050565b91508682600081518110611cbb57fe5b60200260200101511115611d08576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b611d1c3361117388886000818110610e7057fe5b611d5b82878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250309250612cac915050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316632e1a7d4d83600185510381518110611d9a57fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611dd857600080fd5b505af1158015611dec573d6000803e3d6000fd5b505050506111bf8483600185510381518110611e0457fe5b60200260200101516128c4565b60608142811015611e5c576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216611e998787600019810181811061091c57fe5b6001600160a01b031614611eec576040805162461bcd60e51b815260206004820152601560248201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604482015290519081900360640190fd5b611f2a8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612e72915050565b91508682600184510381518110611f3d57fe5b60200260200101511015611d08576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e8813525397d3d55560821b604482015290519081900360640190fd5b60608142811015611fd6576040805162461bcd60e51b815260206004820152601060248201526f13949bdd5d195c8e881156141254915160821b604482015290519081900360640190fd5b6120148686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c9250612b07915050565b9150868260008151811061202457fe5b6020026020010151111561115f576040805162461bcd60e51b815260206004820152600f60248201526e272937baba32b91d1026a0ac2fa4a760891b604482015290519081900360640190fd5b600061207f8a333087612fa8565b60008a6001600160a01b031663cc77828d6040518163ffffffff1660e01b815260040160006040518083038186803b1580156120ba57600080fd5b505afa1580156120ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120f691908101906146cd565b8051909150861480156121095750805188145b6121255760405162461bcd60e51b815260040161059c90614a64565b60405163b02f0b7360e01b81526001600160a01b038c169063b02f0b73906121559088908d908d90600401614b2b565b600060405180830381600087803b15801561216f57600080fd5b505af1158015612183573d6000803e3d6000fd5b5050604080516003808252608082019092526000935091506020820160608036833701905050905060005b82518110156122025760006121eb8483815181106121c857fe5b60200260200101518b8b858181106121dc57fe5b905060200201358f868a61353d565b90506121f7858261373f565b9450506001016121ae565b50848310156122235760405162461bcd60e51b815260040161059c90614ac1565b50509998505050505050505050565b60006122496001600160a01b038716333088612fa8565b60006122558585612b07565b9050866001600160a01b03166302c967486122838760008151811061227657fe5b6020026020010151612b01565b8360008151811061229057fe5b6020026020010151896040518463ffffffff1660e01b81526004016122b7939291906149a1565b602060405180830381600087803b1580156122d157600080fd5b505af11580156122e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612309919061487a565b915061236a61231e8660008151811061227657fe5b6123508760008151811061232e57fe5b60200260200101518860018151811061234357fe5b6020026020010151612c52565b8360008151811061235d57fe5b602002602001015161275b565b612375818685612cac565b610b9a33612383888561296f565b6001600160a01b038a16919061275b565b6000816123e8576040805162461bcd60e51b815260206004820152600c60248201527f4552525f4449565f5a45524f0000000000000000000000000000000000000000604482015290519081900360640190fd5b670de0b6b3a764000083028315806124105750670de0b6b3a764000084828161240d57fe5b04145b612454576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b600283048101818110156124a2576040805162461bcd60e51b815260206004820152601060248201526f11549497d1125597d25395115493905360821b604482015290519081900360640190fd5b60008482816124ad57fe5b0493505050505b92915050565b60089190911b1790565b60008060006124d98660008151811061227657fe5b90506000896001600160a01b0316634aa4e0b5896040518263ffffffff1660e01b8152600401612509919061498d565b60206040518083038186803b15801561252157600080fd5b505afa158015612535573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612559919061487a565b90506125658682613797565b9350876001600160a01b0316826001600160a01b031614156125bb5760408051808201909152600f81526e272937baba32b91d1026a0ac2fa4a760891b60208201526125b49086908690613859565b925061273a565b74ffffffffffffffffffffffffffffffffffffffffff89169860a81c6125ea6001600160a01b038416826124ba565b886000815181106125f757fe5b60209081029190910101528961263d576002885261261f6001600160a01b038a1660006124ba565b8860018151811061262c57fe5b602002602001018181525050612676565b60038852604088018a905261265c6001600160a01b038a1660006124ba565b8860028151811061266957fe5b6020026020010181815250505b60006126828987612b07565b90506126d48160008151811061269457fe5b60200260200101516040518060400160405280600f81526020016e272937baba32b91d1026a0ac2fa4a760891b815250896138599092919063ffffffff16565b945061272c6126fe8a6000815181106126e957fe5b60200260200101518b60018151811061234357fe5b8260008151811061270b57fe5b6020026020010151866001600160a01b031661275b9092919063ffffffff16565b612737818a30612cac565b50505b61274e6001600160a01b0389168b866138f1565b5050965096945050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b602083106127d75780518252601f1990920191602091820191016127b8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612839576040519150601f19603f3d011682016040523d82523d6000602084013e61283e565b606091505b509150915081801561286c57508051158061286c575080806020019051602081101561286957600080fd5b50515b6128bd576040805162461bcd60e51b815260206004820152600560248201527f54483a5354000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b6040516000906001600160a01b0384169083908381818185875af1925050503d806000811461290f576040519150601f19603f3d011682016040523d82523d6000602084013e612914565b606091505b505090508061296a576040805162461bcd60e51b815260206004820152600660248201527f54483a5354450000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050565b808203828111156124b4576040805162461bcd60e51b815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b60006129d586333088612fa8565b6000866001600160a01b03166346ab38f16129f68760008151811061227657fe5b8860006040518463ffffffff1660e01b8152600401612a17939291906149a1565b602060405180830381600087803b158015612a3157600080fd5b505af1158015612a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a69919061487a565b90506000612a778683612e72565b905080600182510381518110612a8957fe5b6020026020010151925084831015612ab35760405162461bcd60e51b815260040161059c90614ac1565b612aeb612ac68760008151811061227657fe5b61235088600081518110612ad657fe5b60200260200101518960018151811061234357fe5b612af6818786612cac565b505095945050505050565b60081c90565b6060600283511015612b60576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b825167ffffffffffffffff81118015612b7857600080fd5b50604051908082528060200260200182016040528015612ba2578160200160208202803683370190505b5090508181600183510381518110612bb657fe5b60209081029190910101528251600019015b8015612c4b57600080612c04866001850381518110612be357fe5b6020026020010151878581518110612bf757fe5b6020026020010151613a53565b91509150612c26848481518110612c1757fe5b60200260200101518383613b03565b846001850381518110612c3557fe5b6020908102919091010152505060001901612bc8565b5092915050565b6000806000612c6085613bd1565b915091506000612c6f85612b01565b9050600080612c7e8584613bdf565b9150915083612c9657612c918282613cbd565b612ca0565b612ca08282613d9a565b98975050505050505050565b60005b6001835103811015611a4e57600080848381518110612cca57fe5b6020026020010151858460010181518110612ce157fe5b6020026020010151915091506000868460010181518110612cfe57fe5b60200260200101519050600080838510612d1a57826000612d1e565b6000835b91509150600060028951038710612d355787612d48565b612d48858a896002018151811061234357fe5b9050612d548686612c52565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015612d91576020820181803683370190505b506040518563ffffffff1660e01b815260040180858152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612df9578181015183820152602001612de1565b50505050905090810190601f168015612e265780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015612e4857600080fd5b505af1158015612e5c573d6000803e3d6000fd5b505060019098019750612caf9650505050505050565b6060600283511015612ecb576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a20494e56414c49445f504154480000604482015290519081900360640190fd5b825167ffffffffffffffff81118015612ee357600080fd5b50604051908082528060200260200182016040528015612f0d578160200160208202803683370190505b5090508181600081518110612f1e57fe5b60200260200101818152505060005b6001845103811015612c4b57600080612f62868481518110612f4b57fe5b6020026020010151878560010181518110612bf757fe5b91509150612f84848481518110612f7557fe5b60200260200101518383613e77565b848460010181518110612f9357fe5b60209081029190910101525050600101612f2d565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b6020831061302c5780518252601f19909201916020918201910161300d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461308e576040519150601f19603f3d011682016040523d82523d6000602084013e613093565b606091505b50915091508180156130c15750805115806130c157508080602001905160208110156130be57600080fd5b50515b613112576040805162461bcd60e51b815260206004820152600660248201527f54483a5354460000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b505050505050565b60006131278584866138f1565b604051635db3427760e01b81526001600160a01b03841690635db3427790613157908890889087906004016149a1565b602060405180830381600087803b15801561317157600080fd5b505af1158015613185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a9919061487a565b905061084b83338361275b565b600080846001600160a01b03166364c7d661856040518263ffffffff1660e01b81526004016131e5919061498d565b60e06040518083038186803b1580156131fd57600080fd5b505afa158015613211573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323591906147d5565b90508060200151613321576040516391bfa2bf60e01b81526000906001600160a01b038716906391bfa2bf9061326f90889060040161498d565b60206040518083038186803b15801561328757600080fd5b505afa15801561329b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132bf919061487a565b905060006132da6132d4838560c00151613f4f565b83612394565b905060006132ef6658d15e1762800083613797565b60c08501849052905061330a6703782dace9d9000082613fb5565b6bffffffffffffffffffffffff1660608501525050505b6000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561335c57600080fd5b505afa158015613370573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613394919061487a565b90506000866001600160a01b031663936c34776040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d157600080fd5b505afa1580156133e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613409919061487a565b90506000876001600160a01b031663d4cadf686040518163ffffffff1660e01b815260040160206040518083038186803b15801561344657600080fd5b505afa15801561345a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061347e919061487a565b9050612ca08460c0015185606001516bffffffffffffffffffffffff1685858a86614016565b6134af8483856138f1565b60405163036836fd60e51b81526001600160a01b03831690636d06dfa0906134df908790859088906004016149a1565b602060405180830381600087803b1580156134f957600080fd5b505af115801561350d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613531919061487a565b50611a4e82338361275b565b600080866001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161356c919061498d565b60206040518083038186803b15801561358457600080fd5b505afa158015613598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bc919061487a565b9050846001600160a01b0316876001600160a01b03161415613604579050806001600160a01b03831630146135ff576135ff6001600160a01b038816848361275b565b610b9a565b74ffffffffffffffffffffffffffffffffffffffffff86169560a81c6136336001600160a01b038916826124ba565b8560008151811061364057fe5b60209081029190910101528661368657600285526136686001600160a01b03871660006124ba565b8560018151811061367557fe5b6020026020010181815250506136bf565b60038552604085018790526136a56001600160a01b03871660006124ba565b856002815181106136b257fe5b6020026020010181815250505b60006136cb8684612e72565b905061370e6136e08760008151811061232e57fe5b826000815181106136ed57fe5b60200260200101518b6001600160a01b031661275b9092919063ffffffff16565b613719818787612cac565b8060018251038151811061372957fe5b6020026020010151935050505095945050505050565b808201828110156124b4576040805162461bcd60e51b815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008282028315806137b15750828482816137ae57fe5b04145b6137f5576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6706f05b59d3b20000810181811015613848576040805162461bcd60e51b815260206004820152601060248201526f4552525f4d554c5f4f564552464c4f5760801b604482015290519081900360640190fd5b6000670de0b6b3a7640000826124ad565b81830381848211156138e95760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156138ae578181015183820152602001613896565b50505050905090810190601f1680156138db5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1781529251825160009485949389169392918291908083835b6020831061396d5780518252601f19909201916020918201910161394e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146139cf576040519150601f19603f3d011682016040523d82523d6000602084013e6139d4565b606091505b5091509150818015613a02575080511580613a0257508080602001905160208110156139ff57600080fd5b50515b6128bd576040805162461bcd60e51b815260206004820152600560248201527f54483a5341000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600080600080613a638686612c52565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613a9b57600080fd5b505afa158015613aaf573d6000803e3d6000fd5b505050506040513d6060811015613ac557600080fd5b5080516020909101516dffffffffffffffffffffffffffff9182169350169050848610613af3578082613af6565b81815b9097909650945050505050565b6000808411613b435760405162461bcd60e51b815260040180806020018281038252602c815260200180614bdb602c913960400191505060405180910390fd5b600083118015613b535750600082115b613b8e5760405162461bcd60e51b8152600401808060200182810382526028815260200180614c2c6028913960400191505060405180910390fd5b6000613ba66103e8613ba086886140c9565b906140c9565b90506000613bba6103e5613ba0868961296f565b905061047e6001828481613bca57fe5b049061373f565b600881901c9160ff90911690565b600080826001600160a01b0316846001600160a01b03161415613c335760405162461bcd60e51b8152600401808060200182810382526025815260200180614c076025913960400191505060405180910390fd5b826001600160a01b0316846001600160a01b031610613c53578284613c56565b83835b90925090506001600160a01b038216613cb6576040805162461bcd60e51b815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f414444524553530000604482015290519081900360640190fd5b9250929050565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401527f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f90951b166069820152607d8101939093527f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f609d808501919091528151808503909101815260bd9093019052815191012090565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501207fff0000000000000000000000000000000000000000000000000000000000000060688401527f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac90951b166069820152607d8101939093527fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303609d808501919091528151808503909101815260bd9093019052815191012090565b6000808411613eb75760405162461bcd60e51b815260040180806020018281038252602b815260200180614c54602b913960400191505060405180910390fd5b600083118015613ec75750600082115b613f025760405162461bcd60e51b8152600401808060200182810382526028815260200180614c2c6028913960400191505060405180910390fd5b6000613f10856103e56140c9565b90506000613f1e82856140c9565b90506000613f3883613f32886103e86140c9565b9061373f565b9050808281613f4357fe5b04979650505050505050565b6000806000613f5e8585614135565b9150915080156138e9576040805162461bcd60e51b815260206004820152601160248201527f4552525f5355425f554e444552464c4f57000000000000000000000000000000604482015290519081900360640190fd5b60008282018381101561400f576040805162461bcd60e51b815260206004820152601060248201527f4552525f4144445f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b6000806140238786612394565b905060006140318786613fb5565b9050600061403f8289612394565b90506000614055670de0b6b3a764000085612394565b905060006140638383614157565b90506000614071828e613797565b9050600061407f828f613f4f565b9050600061409e614098670de0b6b3a76400008a613f4f565b8b613797565b90506140b682610663670de0b6b3a764000084613f4f565b9f9e505050505050505050505050505050565b60008115806140e4575050808202828282816140e157fe5b04145b6124b4576040805162461bcd60e51b815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b60008082841061414b5750508082036000613cb6565b50508181036001613cb6565b600060018310156141af576040805162461bcd60e51b815260206004820152601560248201527f4552525f42504f575f424153455f544f4f5f4c4f570000000000000000000000604482015290519081900360640190fd5b671bc16d674ec7ffff83111561420c576040805162461bcd60e51b815260206004820152601660248201527f4552525f42504f575f424153455f544f4f5f4849474800000000000000000000604482015290519081900360640190fd5b600061421783614269565b905060006142258483613f4f565b9050600061423b8661423685614286565b614294565b90508161424c5792506124b4915050565b600061425d87846305f5e1006142eb565b905061161c8282613797565b6000670de0b6b3a764000061427d83614286565b0290505b919050565b670de0b6b3a7640000900490565b600080600283066142ad57670de0b6b3a76400006142af565b835b90506002830492505b821561400f576142c88485613797565b935060028306156142e0576142dd8185613797565b90505b6002830492506142b8565b600082818061430287670de0b6b3a7640000614135565b9092509050670de0b6b3a764000080600060015b8884106143bf576000670de0b6b3a76400008202905060008061434a8a61434585670de0b6b3a7640000613f4f565b614135565b915091506143618761435c848c613797565b613797565b965061436d8784612394565b96508661437c575050506143bf565b8715614386579315935b8015614390579315935b84156143a7576143a08688613f4f565b95506143b4565b6143b18688613fb5565b95505b505050600101614316565b50909998505050505050505050565b60008083601f8401126143df578182fd5b50813567ffffffffffffffff8111156143f6578182fd5b6020830191508360208083028501011115613cb657600080fd5b8051801515811461428157600080fd5b805164ffffffffff8116811461428157600080fd5b805160ff8116811461428157600080fd5b80516bffffffffffffffffffffffff8116811461428157600080fd5b60008060008060608587031215614477578384fd5b843561448281614bc2565b9350602085013567ffffffffffffffff81111561449d578384fd5b6144a9878288016143ce565b9598909750949560400135949350505050565b60008060008060008060a087890312156144d4578182fd5b86356144df81614bc2565b9550602087013567ffffffffffffffff8111156144fa578283fd5b61450689828a016143ce565b90965094505060408701359250606087013561452181614bc2565b80925050608087013590509295509295509295565b60008060008060008060008060c0898b031215614551578182fd5b883561455c81614bc2565b9750602089013567ffffffffffffffff80821115614578578384fd5b6145848c838d016143ce565b909950975060408b013591508082111561459c578384fd5b506145a98b828c016143ce565b9096509450506060890135925060808901356145c481614bc2565b8092505060a089013590509295985092959890939650565b600080600080600080600060a0888a0312156145f6578283fd5b873561460181614bc2565b9650602088013567ffffffffffffffff8082111561461d578485fd5b6146298b838c016143ce565b909850965060408a0135915080821115614641578485fd5b5061464e8a828b016143ce565b989b979a5095989597966060870135966080013595509350505050565b600080600080600060808688031215614682578081fd5b853561468d81614bc2565b945060208601359350604086013567ffffffffffffffff8111156146af578182fd5b6146bb888289016143ce565b96999598509660600135949350505050565b600060208083850312156146df578182fd5b825167ffffffffffffffff808211156146f6578384fd5b818501915085601f830112614709578384fd5b81518181111561471557fe5b8381029150614725848301614b9e565b8181528481019084860184860187018a101561473f578788fd5b8795505b8386101561476d578051945061475885614bc2565b84835260019590950194918601918601614743565b5098975050505050505050565b6000806000806060858703121561478f578182fd5b843567ffffffffffffffff8111156147a5578283fd5b6147b1878288016143ce565b90955093505060208501356147c581614bc2565b9396929550929360400135925050565b600060e082840312156147e6578081fd5b60405160e0810181811067ffffffffffffffff8211171561480357fe5b60405261480f83614410565b815261481d60208401614410565b602082015261482e60408401614420565b604082015261483f60608401614446565b606082015261485060808401614446565b608082015261486160a08401614435565b60a082015260c083015160c08201528091505092915050565b60006020828403121561488b578081fd5b5051919050565b6000806000806000608086880312156148a9578283fd5b85359450602086013567ffffffffffffffff8111156148c6578384fd5b6148d2888289016143ce565b90955093505060408601356148e681614bc2565b949793965091946060013592915050565b60008060008060008060a0878903121561490f578384fd5b8635955060208701359450604087013567ffffffffffffffff811115614933578485fd5b61493f89828a016143ce565b909550935050606087013561452181614bc2565b6000815180845260208085019450808401835b8381101561498257815187529582019590820190600101614966565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020825261400f6020830184614953565b6020808252600c908201527f494e56414c49445f504154480000000000000000000000000000000000000000604082015260600190565b60208082526015908201527409ca4deeae8cae47440929cac82989288bea082a89605b1b604082015260600190565b6020808252600f908201526e272937baba32b91d1026a0ac2fa4a760891b604082015260600190565b6020808252602c908201527f496e6465786564556e6973776170526f757465724275726e65723a204241445f60408201527f41525241595f4c454e4754480000000000000000000000000000000000000000606082015260800190565b60208082526010908201526f13949bdd5d195c8e8813525397d3d55560821b604082015260600190565b60208082526010908201527f4e526f757465723a204152525f4c454e00000000000000000000000000000000604082015260600190565b90815260200190565b6000848252604060208301528260408301527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614b69578081fd5b6020830280856060850137919091016060019081529392505050565b60008382526040602083015261084b6040830184614953565b60405181810167ffffffffffffffff81118282101715614bba57fe5b604052919050565b6001600160a01b0381168114614bd757600080fd5b5056fe556e697377617056324c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056324c6962726172793a204944454e544943414c5f414444524553534553556e697377617056324c6962726172793a20494e53554646494349454e545f4c4951554944495459556e697377617056324c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e54a164736f6c6343000706000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : _uniswapFactory (address): 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Arg [1] : _sushiswapFactory (address): 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac
Arg [2] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
Arg [1] : 000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.