Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 26 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap Exact ETH F... | 16546920 | 1116 days ago | IN | 0.001 ETH | 0.00306973 | ||||
| Add Liquidity ET... | 15838851 | 1214 days ago | IN | 0.01 ETH | 0.04965662 | ||||
| Swap Exact ETH F... | 15319050 | 1292 days ago | IN | 0.0001 ETH | 0.00251481 | ||||
| Swap Exact ETH F... | 15319046 | 1292 days ago | IN | 0.0001 ETH | 0.00282862 | ||||
| Remove Liquidity | 14995181 | 1344 days ago | IN | 0 ETH | 0.00299869 | ||||
| Remove Liquidity | 14995100 | 1344 days ago | IN | 0 ETH | 0.00540051 | ||||
| Remove Liquidity | 14954334 | 1351 days ago | IN | 0 ETH | 0.0080325 | ||||
| Add Liquidity | 14841485 | 1369 days ago | IN | 0 ETH | 0.05735944 | ||||
| Add Liquidity | 14841429 | 1369 days ago | IN | 0 ETH | 0.05746064 | ||||
| Add Liquidity | 14841406 | 1369 days ago | IN | 0 ETH | 0.05809893 | ||||
| Add Liquidity | 14841369 | 1369 days ago | IN | 0 ETH | 0.05427275 | ||||
| Add Liquidity | 14841336 | 1369 days ago | IN | 0 ETH | 0.08269841 | ||||
| Add Liquidity ET... | 14841330 | 1369 days ago | IN | 0.01 ETH | 0.08093854 | ||||
| Add Liquidity ET... | 14840160 | 1370 days ago | IN | 0.01 ETH | 0.08749461 | ||||
| Swap Tokens For ... | 14836658 | 1370 days ago | IN | 0 ETH | 0.01035056 | ||||
| Swap Exact Token... | 14836644 | 1370 days ago | IN | 0 ETH | 0.00986174 | ||||
| Swap Exact Token... | 14836638 | 1370 days ago | IN | 0 ETH | 0.01450625 | ||||
| Swap Exact Token... | 14836635 | 1370 days ago | IN | 0 ETH | 0.01155401 | ||||
| Swap Exact Token... | 14836623 | 1370 days ago | IN | 0 ETH | 0.01715275 | ||||
| Swap Exact Token... | 14829903 | 1371 days ago | IN | 0 ETH | 0.00456628 | ||||
| Add Liquidity | 14829271 | 1371 days ago | IN | 0 ETH | 0.04998305 | ||||
| Add Liquidity | 14829227 | 1371 days ago | IN | 0 ETH | 0.04172076 | ||||
| Add Liquidity | 14816480 | 1373 days ago | IN | 0 ETH | 0.00318393 | ||||
| Add Liquidity | 14810417 | 1374 days ago | IN | 0 ETH | 0.09263219 | ||||
| Set Utilities | 14809815 | 1375 days ago | IN | 0 ETH | 0.00129803 |
Latest 8 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
|||
|---|---|---|---|---|---|---|---|
| Deposit | 21628729 | 404 days ago | 0.00339882 ETH | ||||
| Swap Exact ETH F... | 21628729 | 404 days ago | 0.00339882 ETH | ||||
| Deposit | 16546920 | 1116 days ago | 0.001 ETH | ||||
| Deposit | 15838851 | 1214 days ago | 0.01 ETH | ||||
| Deposit | 15319050 | 1292 days ago | 0.0001 ETH | ||||
| Deposit | 15319046 | 1292 days ago | 0.0001 ETH | ||||
| - | 14841330 | 1369 days ago | 0.01 ETH | ||||
| - | 14840160 | 1370 days ago | 0.01 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ImpossibleRouter
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;
import './libraries/TransferHelper.sol';
import './libraries/ReentrancyGuard.sol';
import './libraries/ImpossibleLibrary.sol';
import './libraries/SafeMath.sol';
import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleRouterExtension.sol';
import './interfaces/IImpossibleRouter.sol';
import './interfaces/IERC20.sol';
import './interfaces/IWETH.sol';
import './interfaces/IImpossibleWrappedToken.sol';
import './interfaces/IImpossibleWrapperFactory.sol';
/**
@title Router for Impossible Swap V3
@author Impossible Finance
@notice This router builds upon basic Uni V2 Router02 by allowing custom
calculations based on settings in pairs (uni/xybk/custom fees)
@dev See documentation at: https://docs.impossible.finance/impossible-swap/overview
@dev Very little logical changes made in Router02. Most changes to accomodate xybk are in Library
*/
contract ImpossibleRouter is IImpossibleRouter, ReentrancyGuard {
using SafeMath for uint256;
address public immutable override factory;
address public immutable override wrapFactory;
address private utilitySettingAdmin;
address public override routerExtension; // Can be set by utility setting admin once only
address public override WETH; // Can be set by utility setting admin once only
modifier ensure(uint256 deadline) {
require(deadline >= block.timestamp, 'ImpossibleRouter: EXPIRED');
_;
}
/**
@notice Constructor for IF Router
@param _pairFactory Address of IF Pair Factory
@param _wrapFactory Address of IF
@param _utilitySettingAdmin Admin address allowed to set addresses of utility contracts (once)
*/
constructor(
address _pairFactory,
address _wrapFactory,
address _utilitySettingAdmin
) {
factory = _pairFactory;
wrapFactory = _wrapFactory;
utilitySettingAdmin = _utilitySettingAdmin;
}
receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}
/**
@notice Used to set addresses of utility contracts
@dev Only allows setter to set these addresses once for trustlessness
@dev Must set both WETH and routerExtension at the same time, else swap will be bricked
@param _WETH address of WETH contract
@param _routerExtension address of router interface contract
*/
function setUtilities(address _WETH, address _routerExtension) public {
require(WETH == address(0x0) && routerExtension == address(0x0));
require(msg.sender == utilitySettingAdmin, 'IF: ?');
WETH = _WETH;
routerExtension = _routerExtension;
}
/**
@notice Helper function for sending tokens that might need to be wrapped
@param token The address of the token that might have a wrapper
@param src The source to take underlying tokens from
@param dst The destination to send wrapped tokens to
@param amt The amount of tokens to send (wrapped tokens, not underlying)
*/
function wrapSafeTransfer(
address token,
address src,
address dst,
uint256 amt
) internal {
address underlying = IImpossibleWrapperFactory(wrapFactory).wrappedTokensToTokens(token);
if (underlying == address(0x0)) {
TransferHelper.safeTransferFrom(token, src, dst, amt);
} else {
uint256 underlyingAmt = IImpossibleWrappedToken(token).amtToUnderlyingAmt(amt);
TransferHelper.safeTransferFrom(underlying, src, address(this), underlyingAmt);
TransferHelper.safeApprove(underlying, token, underlyingAmt);
IImpossibleWrappedToken(token).deposit(dst, underlyingAmt);
}
}
/**
@notice Helper function for sending tokens that might need to be unwrapped
@param token The address of the token that might be wrapped
@param dst The destination to send underlying tokens to
@param amt The amount of wrapped tokens to send (wrapped tokens, not underlying)
*/
function unwrapSafeTransfer(
address token,
address dst,
uint256 amt
) internal {
address underlying = IImpossibleWrapperFactory(wrapFactory).wrappedTokensToTokens(token);
if (underlying == address(0x0)) {
TransferHelper.safeTransfer(token, dst, amt);
} else {
IImpossibleWrappedToken(token).withdraw(dst, amt);
}
}
/**
@notice Swap function - receive maximum output given fixed input
@dev Openzeppelin reentrancy guards
@param amountIn The exact input amount`
@param amountOutMin The minimum output amount allowed for a successful swap
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
amounts = ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
unwrapSafeTransfer(path[path.length - 1], to, amounts[amounts.length - 1]);
}
/**
@notice Swap function - receive desired output amount given a maximum input amount
@dev Openzeppelin reentrancy guards
@param amountOut The exact output amount desired
@param amountInMax The maximum input amount allowed for a successful swap
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
unwrapSafeTransfer(path[path.length - 1], to, amountOut);
}
/**
@notice Swap function - receive maximum output given fixed input of ETH
@dev Openzeppelin reentrancy guards
@param amountOutMin The minimum output amount allowed for a successful swap
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
amounts = ImpossibleLibrary.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
unwrapSafeTransfer(path[path.length - 1], to, amounts[amounts.length - 1]);
}
/**
@notice Swap function - receive desired ETH output amount given a maximum input amount
@dev Openzeppelin reentrancy guards
@param amountOut The exact output amount desired
@param amountInMax The maximum input amount allowed for a successful swap
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
/**
@notice Swap function - receive maximum ETH output given fixed input of tokens
@dev Openzeppelin reentrancy guards
@param amountIn The amount of input tokens
@param amountOutMin The minimum ETH output amount required for successful swaps
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
amounts = ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]);
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
/**
@notice Swap function - receive maximum tokens output given fixed ETH input
@dev Openzeppelin reentrancy guards
@param amountOut The minimum output amount in tokens required for successful swaps
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
@return amounts Array of actual output token amounts received per swap, sequentially.
*/
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable virtual override ensure(deadline) nonReentrant returns (uint256[] memory amounts) {
require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
amounts = ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'ImpossibleRouter: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amounts[0]));
IImpossibleRouterExtension(routerExtension).swap(amounts, path);
unwrapSafeTransfer(path[path.length - 1], to, amountOut);
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
/**
@notice Swap function for fee on transfer tokens, no WETH/WBNB
@param amountIn The amount of input tokens
@param amountOutMin The minimum token output amount required for successful swaps
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
*/
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant {
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn);
IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
uint256 balance = IERC20(path[path.length - 1]).balanceOf(address(this));
require(balance >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
unwrapSafeTransfer(path[path.length - 1], to, balance);
}
/**
@notice Swap function for fee on transfer tokens with WETH/WBNB
@param amountOutMin The minimum underlying token output amount required for successful swaps
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
*/
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable virtual override ensure(deadline) nonReentrant {
require(path[0] == WETH, 'ImpossibleRouter: INVALID_PATH');
uint256 amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn));
IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
uint256 balance = IERC20(path[path.length - 1]).balanceOf(address(this));
require(balance >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
unwrapSafeTransfer(path[path.length - 1], to, balance);
}
/**
@notice Swap function for fee on transfer tokens, no WETH/WBNB
@param amountIn The amount of input tokens
@param amountOutMin The minimum ETH output amount required for successful swaps
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@param to The address that receives the output tokens
@param deadline The block number after which this transaction is invalid
*/
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external virtual override ensure(deadline) nonReentrant {
require(path[path.length - 1] == WETH, 'ImpossibleRouter: INVALID_PATH');
wrapSafeTransfer(path[0], msg.sender, ImpossibleLibrary.pairFor(factory, path[0], path[1]), amountIn);
IImpossibleRouterExtension(routerExtension).swapSupportingFeeOnTransferTokens(path);
uint256 amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'ImpossibleRouter: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
/**
@notice Function for basic add liquidity functionality
@dev Openzeppelin reentrancy guards
@param tokenA The address of underlying tokenA to add
@param tokenB The address of underlying tokenB to add
@param amountADesired The desired amount of tokenA to add
@param amountBDesired The desired amount of tokenB to add
@param amountAMin The min amount of tokenA to add (amountAMin:amountBDesired sets bounds on ratio)
@param amountBMin The min amount of tokenB to add (amountADesired:amountBMin sets bounds on ratio)
@param to The address to mint LP tokens to
@param deadline The block number after which this transaction is invalid
@return amountA Amount of tokenA added as liquidity to pair
@return amountB Actual amount of tokenB added as liquidity to pair
@return liquidity Actual amount of LP tokens minted
*/
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
virtual
override
ensure(deadline)
nonReentrant
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
)
{
(amountA, amountB) = IImpossibleRouterExtension(routerExtension).addLiquidity(
tokenA,
tokenB,
amountADesired,
amountBDesired,
amountAMin,
amountBMin
);
address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
wrapSafeTransfer(tokenA, msg.sender, pair, amountA);
wrapSafeTransfer(tokenB, msg.sender, pair, amountB);
liquidity = IImpossiblePair(pair).mint(to);
}
/**
@notice Function for add liquidity functionality with 1 token being WETH/WBNB
@dev Openzeppelin reentrancy guards
@param token The address of the non-ETH underlying token to add
@param amountTokenDesired The desired amount of non-ETH underlying token to add
@param amountTokenMin The min amount of non-ETH underlying token to add (amountTokenMin:ETH sent sets bounds on ratio)
@param amountETHMin The min amount of WETH/WBNB to add (amountTokenDesired:amountETHMin sets bounds on ratio)
@param to The address to mint LP tokens to
@param deadline The block number after which this transaction is invalid
@return amountToken Amount of non-ETH underlying token added as liquidity to pair
@return amountETH Actual amount of WETH/WBNB added as liquidity to pair
@return liquidity Actual amount of LP tokens minted
*/
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
virtual
override
ensure(deadline)
nonReentrant
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
)
{
(amountToken, amountETH) = IImpossibleRouterExtension(routerExtension).addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
wrapSafeTransfer(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IImpossiblePair(pair).mint(to);
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); // refund dust eth, if any
}
/**
@notice Function for basic remove liquidity functionality
@dev Openzeppelin reentrancy guards
@param tokenA The address of underlying tokenA in LP token
@param tokenB The address of underlying tokenB in LP token
@param liquidity The amount of LP tokens to burn
@param amountAMin The min amount of underlying tokenA that has to be received
@param amountBMin The min amount of underlying tokenB that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@return amountA Actual amount of underlying tokenA received
@return amountB Actual amount of underlying tokenB received
*/
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) public virtual override ensure(deadline) nonReentrant returns (uint256 amountA, uint256 amountB) {
address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(amountA, amountB) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
tokenA,
tokenB,
pair,
amountAMin,
amountBMin
);
unwrapSafeTransfer(tokenA, to, amountA);
unwrapSafeTransfer(tokenB, to, amountB);
}
/**
@notice Function for remove liquidity functionality with 1 token being WETH/WBNB
@dev Openzeppelin reentrancy guards
@param token The address of the non-ETH underlying token to receive
@param liquidity The amount of LP tokens to burn
@param amountTokenMin The desired amount of non-ETH underlying token that has to be received
@param amountETHMin The min amount of ETH that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@return amountToken Actual amount of non-ETH underlying token received
@return amountETH Actual amount of WETH/WBNB received
*/
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) public virtual override ensure(deadline) nonReentrant returns (uint256 amountToken, uint256 amountETH) {
address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(amountToken, amountETH) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
token,
WETH,
pair,
amountTokenMin,
amountETHMin
);
unwrapSafeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
/**
@notice Function for remove liquidity functionality using EIP712 permit
@dev Openzeppelin reentrancy guards
@param tokenA The address of underlying tokenA in LP token
@param tokenB The address of underlying tokenB in LP token
@param liquidity The amount of LP tokens to burn
@param amountAMin The min amount of underlying tokenA that has to be received
@param amountBMin The min amount of underlying tokenB that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@param approveMax How much tokens are approved for transfer (liquidity, or max)
@param v,r,s Variables that construct a valid EVM signature
@return amountA Actual amount of underlying tokenA received
@return amountB Actual amount of underlying tokenB received
*/
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint256 amountA, uint256 amountB) {
address pair = ImpossibleLibrary.pairFor(factory, tokenA, tokenB);
uint256 value = approveMax ? uint256(-1) : liquidity;
IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
return removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
/**
@notice Function for remove liquidity functionality using EIP712 permit with 1 token being WETH/WBNB
@param token The address of the non-ETH underlying token to receive
@param liquidity The amount of LP tokens to burn
@param amountTokenMin The desired amount of non-ETH underlying token that has to be received
@param amountETHMin The min amount of ETH that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@param approveMax How much tokens are approved for transfer (liquidity, or max)
@param v,r,s Variables that construct a valid EVM signature
@return amountToken Actual amount of non-ETH underlying token received
@return amountETH Actual amount of WETH/WBNB received
*/
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint256 amountToken, uint256 amountETH) {
address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
uint256 value = approveMax ? uint256(-1) : liquidity;
IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
/**
@notice Function for remove liquidity functionality with 1 token being WETH/WBNB
@dev This is used when non-WETH/WBNB underlying token is fee-on-transfer: e.g. FEI algo stable v1
@dev Openzeppelin reentrancy guards
@param token The address of the non-ETH underlying token to receive
@param liquidity The amount of LP tokens to burn
@param amountTokenMin The desired amount of non-ETH underlying token that has to be received
@param amountETHMin The min amount of ETH that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@return amountETH Actual amount of WETH/WBNB received
*/
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) public virtual override ensure(deadline) nonReentrant returns (uint256 amountETH) {
address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
IImpossiblePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(, amountETH) = IImpossibleRouterExtension(routerExtension).removeLiquidity(
token,
WETH,
pair,
amountTokenMin,
amountETHMin
);
unwrapSafeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
/**
@notice Function for remove liquidity functionality using EIP712 permit with 1 token being WETH/WBNB
@dev This is used when non-WETH/WBNB underlying token is fee-on-transfer: e.g. FEI algo stable v1
@param token The address of the non-ETH underlying token to receive
@param liquidity The amount of LP tokens to burn
@param amountTokenMin The desired amount of non-ETH underlying token that has to be received
@param amountETHMin The min amount of ETH that has to be received
@param to The address to send underlying tokens to
@param deadline The block number after which this transaction is invalid
@param approveMax How much tokens are approved for transfer (liquidity, or max)
@param v,r,s Variables that construct a valid EVM signature
@return amountETH Actual amount of WETH/WBNB received
*/
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint256 amountETH) {
address pair = ImpossibleLibrary.pairFor(factory, token, WETH);
uint256 value = approveMax ? uint256(-1) : liquidity;
IImpossiblePair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token,
liquidity,
amountTokenMin,
amountETHMin,
to,
deadline
);
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './libraries/SafeMath.sol';
import './interfaces/IImpossibleERC20.sol';
import './interfaces/IERC20.sol';
contract ImpossibleERC20 is IImpossibleERC20 {
using SafeMath for uint256;
string public override name = 'Impossible Swap LPs';
string public override symbol = 'IF-LP';
uint8 public constant override decimals = 18;
uint256 public override totalSupply;
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
bytes32 public override DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant override PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public override nonces;
constructor() {
// Initializes a placeholder name/domain separator for testing permit typehashs
_setupDomainSeparator();
}
function _initBetterDesc(address _token0, address _token1) internal {
// This sets name/symbol to include tokens in LP token
string memory desc = string(abi.encodePacked(IERC20(_token0).symbol(), '/', IERC20(_token1).symbol()));
name = string(abi.encodePacked('Impossible Swap LPs: ', desc));
symbol = string(abi.encodePacked('IF-LP: ', desc));
_setupDomainSeparator();
}
function _setupDomainSeparator() internal {
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external override returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(deadline >= block.timestamp, 'IF: EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'IF: INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
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');
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
interface IImpossibleERC20 {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address 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;
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address 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);
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import '../ImpossibleERC20.sol';
contract ERC20 is ImpossibleERC20 {
constructor(uint256 _totalSupply) {
_mint(msg.sender, _totalSupply);
}
}/// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './ImpossibleERC20.sol';
import './libraries/Math.sol';
import './libraries/ReentrancyGuard.sol';
import './interfaces/IImpossiblePair.sol';
import './interfaces/IERC20.sol';
import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleCallee.sol';
/**
@title Pair contract for Impossible Swap V3
@author Impossible Finance
@notice This factory builds upon basic Uni V2 Pair by adding xybk
invariant, ability to switch between invariants/boost levels,
and ability to set asymmetrical tuning.
@dev See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/
contract ImpossiblePair is IImpossiblePair, ImpossibleERC20, ReentrancyGuard {
using SafeMath for uint256;
uint256 public constant override MINIMUM_LIQUIDITY = 10**3;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
/**
@dev Timestamps, not block numbers
*/
uint256 private constant THIRTY_MINS = 108000;
uint32 private constant TWO_WEEKS = 1209600;
uint32 private constant ONE_DAY = 86400;
/**
@dev tradeFee is fee collected per swap in basis points. Init at 30bp.
*/
uint16 private tradeFee = 30;
/**
@dev tradeState Tracks what directional trades are allowed for this pair.
*/
TradeState private tradeState;
bool private isXybk;
address public override factory;
address public override token0;
address public override token1;
address public router;
address public routerExtension;
uint128 private reserve0;
uint128 private reserve1;
uint256 public kLast;
/**
@dev These are the variables for boost.
@dev Boosts in practice are a function of oldBoost, newBoost, startBlock and endBlock
@dev We linearly interpolate between oldBoost and newBoost over the blocks
@dev Note that governance being able to instantly change boosts is dangerous
@dev Boost0 applies when pool balance0 >= balance1 (when token1 is the more expensive token)
@dev Boost1 applies when pool balance1 > balance0 (when token0 is the more expensive token)
*/
uint32 private oldBoost0 = 1;
uint32 private oldBoost1 = 1;
uint32 private newBoost0 = 1;
uint32 private newBoost1 = 1;
uint32 private currBoost0 = 1;
uint32 private currBoost1 = 1;
/**
@dev BSC mines 10m blocks a year. uint32 will last 400 years before overflowing
*/
uint256 public startTime;
uint256 public endTime;
/**
@dev withdrawalFeeRatio is the fee collected on burn. Init as 1/201=0.4795% fee (if feeOn)
*/
uint256 public withdrawalFeeRatio = 201; //
/**
@dev Delay sets the duration for boost changes over time. Init as 1 day
@dev In test environment, set to 50 blocks.
*/
uint256 public override delay = ONE_DAY;
modifier onlyIFRouter() {
require(msg.sender == router || msg.sender == routerExtension, 'IF: FORBIDDEN');
_;
}
modifier onlyGovernance() {
require(msg.sender == IImpossibleSwapFactory(factory).governance(), 'IF: FORBIDDEN');
_;
}
/**
@notice Gets the fee per swap in basis points, as well as if this pair is uni or xybk
@return _tradeFee Fee per swap in basis points
@return _tradeState What trades are allowed for this pair
@return _isXybk Boolean if this swap is using uniswap or xybk
*/
function getPairSettings()
external
view
override
returns (
uint16 _tradeFee,
TradeState _tradeState,
bool _isXybk
)
{
_tradeFee = tradeFee;
_tradeState = tradeState;
_isXybk = isXybk;
}
/**
@notice Gets the reserves in the pair contract
@return _reserve0 Reserve amount of token0 in the pair
@return _reserve1 Reserve amount of token1 in the pair
*/
function getReserves() public view override returns (uint256 _reserve0, uint256 _reserve1) {
_reserve0 = uint256(reserve0);
_reserve1 = uint256(reserve1);
}
/**
@notice Getter for the stored boost state
@dev Helper function for internal use. If uni invariant, all boosts=1
@return _newBoost0 New boost0 value
@return _newBoost1 New boost1 value
@return _oldBoost0 Old boost0 value
@return _oldBoost1 Old boost1 value
*/
function getBoost()
internal
view
returns (
uint32 _newBoost0,
uint32 _newBoost1,
uint32 _oldBoost0,
uint32 _oldBoost1,
uint32 _currBoost0,
uint32 _currBoost1
)
{
_newBoost0 = newBoost0;
_newBoost1 = newBoost1;
_oldBoost0 = oldBoost0;
_oldBoost1 = oldBoost1;
_currBoost0 = currBoost0;
_currBoost1 = currBoost1;
}
/**
@notice Helper function to calculate a linearly interpolated boost
@dev Calculations: old + |new - old| * (curr-start)/end-start
@param oldBst The old boost
@param newBst The new boost
@param end The endblock which linear interpolation ends at
@return uint256 Linearly interpolated boost value
*/
function linInterpolate(
uint32 oldBst,
uint32 newBst,
uint256 end
) internal view returns (uint256) {
uint256 start = startTime;
if (newBst > oldBst) {
/// old + diff * (curr-start) / (end-start)
return
uint256(oldBst).add(
(uint256(newBst).sub(uint256(oldBst))).mul(block.timestamp.sub(start)).div(end.sub(start))
);
} else {
/// old - diff * (curr-start) / (end-start)
return
uint256(oldBst).sub(
(uint256(oldBst).sub(uint256(newBst))).mul(block.timestamp.sub(start)).div(end.sub(start))
);
}
}
/**
@notice Function to get/calculate actual boosts in the system
@dev If block.timestamp > endBlock, just return new boosts
@return _boost0 The actual boost0 value
@return _boost1 The actual boost1 value
*/
function calcBoost() public view override returns (uint256 _boost0, uint256 _boost1) {
uint256 _endTime = endTime;
if (block.timestamp >= _endTime) {
(uint32 _newBoost0, uint32 _newBoost1, , , , ) = getBoost();
_boost0 = uint256(_newBoost0);
_boost1 = uint256(_newBoost1);
} else {
(
uint32 _newBoost0,
uint32 _newBoost1,
uint32 _oldBoost0,
uint32 _oldBoost1,
uint32 _currBoost0,
uint32 _currBoost1
) = getBoost();
_boost0 = linInterpolate(_oldBoost0, _newBoost0, _endTime);
_boost1 = linInterpolate(_oldBoost1, _newBoost1, _endTime);
if (xybkComputeK(_boost0, _boost1) < kLast) {
_boost0 = _currBoost0;
_boost1 = _currBoost1;
}
}
}
function calcBoostWithUpdate() internal returns (uint256 _boost0, uint256 _boost1) {
(_boost0, _boost1) = calcBoost();
currBoost0 = uint32(_boost0);
currBoost1 = uint32(_boost1);
}
/**
@notice Safe transfer implementation for tokens
@dev Requires the transfer to succeed and return either null or True
@param token The token to transfer
@param to The address to transfer to
@param value The amount of tokens to transfer
*/
function _safeTransfer(
address token,
address to,
uint256 value
) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'IF: TRANSFER_FAILED');
}
/**
@notice Switches pool from uniswap invariant to xybk invariant
@dev Can only be called by IF governance
@dev Requires the pool to be uniswap invariant currently
@param _newBoost0 The new boost0
@param _newBoost1 The new boost1
*/
function makeXybk(uint32 _newBoost0, uint32 _newBoost1) external onlyGovernance nonReentrant {
require(!isXybk, 'IF: IS_ALREADY_XYBK');
_updateBoost(_newBoost0, _newBoost1);
isXybk = true;
emit ChangeInvariant(isXybk, _newBoost0, _newBoost1);
}
/**
@notice Switches pool from xybk invariant to uniswap invariant
@dev Can only be called by IF governance
@dev Requires the pool to be xybk invariant currently
*/
function makeUni() external onlyGovernance nonReentrant {
require(isXybk, 'IF: IS_ALREADY_UNI');
require(block.timestamp >= endTime, 'IF: BOOST_ALREADY_CHANGING');
require(newBoost0 == 1 && newBoost1 == 1, 'IF: INVALID_BOOST');
isXybk = false;
oldBoost0 = 1; // Set boost to 1
oldBoost1 = 1; // xybk with boost=1 is just xy=k formula
emit ChangeInvariant(isXybk, newBoost0, newBoost1);
}
/**
@notice Setter function for trade fee per swap
@dev Can only be called by IF governance
@dev uint8 fee means 255 basis points max, or max trade fee of 2.56%
@dev uint8 type means fee cannot be negative
@param _newFee The new trade fee collected per swap, in basis points
*/
function updateTradeFees(uint8 _newFee) external onlyGovernance {
uint16 _oldFee = tradeFee;
tradeFee = uint16(_newFee);
emit UpdatedTradeFees(_oldFee, _newFee);
}
/**
@notice Setter function for time delay for boost changes
@dev Can only be called by IF governance
@dev Delay must be between 30 minutes and 2 weeks
@param _newDelay The new time delay in seconds
*/
function updateDelay(uint256 _newDelay) external onlyGovernance {
require(_newDelay >= THIRTY_MINS && delay <= TWO_WEEKS, 'IF: INVALID_DELAY');
uint256 _oldDelay = delay;
delay = _newDelay;
emit UpdatedDelay(_oldDelay, _newDelay);
}
/**
@notice Setter function for trade state for this pair
@dev Can only be called by IF governance
@param _tradeState See line 45 for TradeState enum settings
*/
function updateTradeState(TradeState _tradeState) external onlyGovernance nonReentrant {
require(isXybk, 'IF: IS_CURRENTLY_UNI');
tradeState = _tradeState;
emit UpdatedTradeState(_tradeState);
}
/**
@notice Setter function for pool boost state
@dev Can only be called by IF governance
@dev Pool has to be using xybk invariant to update boost
@param _newBoost0 The new boost0
@param _newBoost1 The new boost1
*/
function updateBoost(uint32 _newBoost0, uint32 _newBoost1) external onlyGovernance nonReentrant {
require(isXybk, 'IF: IS_CURRENTLY_UNI');
_updateBoost(_newBoost0, _newBoost1);
}
/**
@notice Internal helper function to change boosts
@dev _newBoost0 and _newBoost1 have to be between 1 and 1000000
@dev Pool cannot already have changing boosts
@param _newBoost0 The new boost0
@param _newBoost1 The new boost1
*/
function _updateBoost(uint32 _newBoost0, uint32 _newBoost1) internal {
require(
_newBoost0 >= 1 && _newBoost1 >= 1 && _newBoost0 <= 1000000 && _newBoost1 <= 1000000,
'IF: INVALID_BOOST'
);
uint256 _blockTimestamp = block.timestamp;
require(_blockTimestamp >= endTime, 'IF: BOOST_ALREADY_CHANGING');
(uint256 _reserve0, uint256 _reserve1) = getReserves();
_mintFee(_reserve0, _reserve1);
oldBoost0 = newBoost0;
oldBoost1 = newBoost1;
newBoost0 = _newBoost0;
newBoost1 = _newBoost1;
startTime = _blockTimestamp;
endTime = _blockTimestamp + delay;
emit UpdatedBoost(oldBoost0, oldBoost1, newBoost0, newBoost1, startTime, endTime);
}
/**
@notice Setter function for the withdrawal fee that goes to Impossible per burn
@dev Can only be called by IF governance
@dev Fee is 1/_newFeeRatio. So <1% is 1/(>=100)
@param _newFeeRatio The new fee ratio
*/
function updateWithdrawalFeeRatio(uint256 _newFeeRatio) external onlyGovernance {
require(_newFeeRatio >= 100, 'IF: INVALID_FEE'); // capped at 1%
uint256 _oldFeeRatio = withdrawalFeeRatio;
withdrawalFeeRatio = _newFeeRatio;
emit UpdatedWithdrawalFeeRatio(_oldFeeRatio, _newFeeRatio);
}
/**
@notice Constructor function for pair address
@dev For pairs associated with IF swap, msg.sender is always the factory
*/
constructor() {
factory = msg.sender;
}
/**
@notice Initialization function by factory on deployment
@dev Can only be called by factory, and will only be called once
@dev _initBetterDesc adds token0/token1 symbols to ERC20 LP name, symbol
@param _token0 Address of token0 in pair
@param _token0 Address of token1 in pair
@param _router Address of trusted IF router
*/
function initialize(
address _token0,
address _token1,
address _router,
address _routerExtension
) external override {
require(msg.sender == factory, 'IF: FORBIDDEN');
router = _router;
routerExtension = _routerExtension;
token0 = _token0;
token1 = _token1;
_initBetterDesc(_token0, _token1);
}
/**
@notice Updates reserve state in pair
@dev No TWAP/oracle functionality
@param balance0 The new balance for token0
@param balance1 The new balance for token1
*/
function _update(uint256 balance0, uint256 balance1) private {
reserve0 = uint128(balance0);
reserve1 = uint128(balance1);
emit Sync(reserve0, reserve1);
}
/**
@notice Mints fee to IF governance multisig treasury
@dev If feeOn, mint liquidity equal to 4/5th of growth in sqrt(K)
@param _reserve0 The latest balance for token0 for fee calculations
@param _reserve1 The latest balance for token1 for fee calculations
@return feeOn If the mint/burn fee is turned on in this pair
*/
function _mintFee(uint256 _reserve0, uint256 _reserve1) private returns (bool feeOn) {
address feeTo = IImpossibleSwapFactory(factory).feeTo();
feeOn = feeTo != address(0);
uint256 oldK = kLast; // gas savings
if (feeOn) {
if (oldK != 0) {
(uint256 _boost0, uint256 _boost1) = calcBoostWithUpdate();
uint256 newRootK = isXybk
? Math.sqrt(xybkComputeK(_boost0, _boost1))
: Math.sqrt(_reserve0.mul(_reserve1));
uint256 oldRootK = Math.sqrt(oldK);
if (newRootK > oldRootK) {
uint256 numerator = totalSupply.mul(newRootK.sub(oldRootK)).mul(4);
uint256 denominator = newRootK.add(oldRootK.mul(4));
uint256 liquidity = numerator / denominator;
if (liquidity > 0) _mint(feeTo, liquidity);
}
}
} else if (oldK != 0) {
kLast = 0;
}
}
/**
@notice Mints LP tokens based on sent underlying tokens. Underlying tokens must already be sent to contract
@dev Function should be called from IF router unless you know what you're doing
@dev Openzeppelin reentrancy guards are used
@dev First mint must have both token0 and token1.
@param to The address to mint LP tokens to
@return liquidity The amount of LP tokens minted
*/
function mint(address to) external override nonReentrant returns (uint256 liquidity) {
(uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
uint256 balance0 = IERC20(token0).balanceOf(address(this));
uint256 balance1 = IERC20(token1).balanceOf(address(this));
uint256 amount0 = balance0.sub(_reserve0);
uint256 amount1 = balance1.sub(_reserve1);
bool feeOn = _mintFee(_reserve0, _reserve1);
uint256 _totalSupply = totalSupply; // gas savings
if (_totalSupply == 0) {
liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
_mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
} else {
liquidity = Math.min(
_reserve0 > 0 ? amount0.mul(_totalSupply) / _reserve0 : uint256(-1),
_reserve1 > 0 ? amount1.mul(_totalSupply) / _reserve1 : uint256(-1)
);
}
require(liquidity > 0, 'IF: INSUFFICIENT_LIQUIDITY_MINTED');
_mint(to, liquidity);
_update(balance0, balance1);
(uint256 _boost0, uint256 _boost1) = calcBoostWithUpdate();
if (feeOn) kLast = isXybk ? xybkComputeK(_boost0, _boost1) : balance0.mul(balance1);
emit Mint(msg.sender, amount0, amount1);
}
/**
@notice Burns LP tokens and returns underlying tokens. LP tokens must already be sent to contract
@dev Function should be called from IF router unless you know what you're doing
@dev Openzeppelin reentrancy guards are used
@param to The address to send underlying tokens to
@return amount0 The amount of token0's sent
@return amount1 The amount of token1's sent
*/
function burn(address to) external override nonReentrant returns (uint256 amount0, uint256 amount1) {
(uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
bool feeOn = _mintFee(_reserve0, _reserve1);
address _token0 = token0; // gas savings
address _token1 = token1; // gas savings
uint256 balance0 = IERC20(_token0).balanceOf(address(this));
uint256 balance1 = IERC20(_token1).balanceOf(address(this));
uint256 liquidity = balanceOf[address(this)];
{
uint256 _totalSupply = totalSupply;
amount0 = liquidity.mul(balance0) / _totalSupply;
amount1 = liquidity.mul(balance1) / _totalSupply;
require(amount0 > 0 || amount1 > 0, 'IF: INSUFFICIENT_LIQUIDITY_BURNED');
address _feeTo = IImpossibleSwapFactory(factory).feeTo();
// Burning fees are paid if burn tx doesnt originate from not IF fee collector
if (feeOn && tx.origin != _feeTo) {
uint256 _feeRatio = withdrawalFeeRatio; // default is 1/201 ~= 0.4975%
amount0 -= amount0.div(_feeRatio);
amount1 -= amount1.div(_feeRatio);
// Transfers withdrawalFee of LP tokens to IF feeTo
uint256 transferAmount = liquidity.div(_feeRatio);
_safeTransfer(address(this), IImpossibleSwapFactory(factory).feeTo(), transferAmount);
_burn(address(this), liquidity.sub(transferAmount));
} else {
_burn(address(this), liquidity);
}
_safeTransfer(_token0, to, amount0);
_safeTransfer(_token1, to, amount1);
}
{
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
_update(balance0, balance1);
if (feeOn) kLast = isXybk ? xybkComputeK(balance0, balance1) : balance0.mul(balance1);
}
emit Burn(msg.sender, amount0, amount1, to);
}
/**
@notice Performs a swap operation. Tokens must already be sent to contract
@dev Input/output amount of tokens must >0 and pool needs to have sufficient liquidity
@dev Openzeppelin reentrancy guards are used
@dev Post-swap invariant check is performed (either uni or xybk)
@param amount0Out The amount of token0's to output
@param amount1Out The amount of token1's to output
@param to The address to output tokens to
@param data Call data allowing for another function call
*/
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external override onlyIFRouter nonReentrant {
require(amount0Out > 0 || amount1Out > 0, 'IF: INSUFFICIENT_OUTPUT_AMOUNT');
(uint256 _reserve0, uint256 _reserve1) = getReserves(); // gas savings
require(amount0Out <= _reserve0 && amount1Out <= _reserve1, 'IF: INSUFFICIENT_LIQUIDITY');
uint256 balance0;
uint256 balance1;
uint256 amount0In;
uint256 amount1In;
{
require(to != token0 && to != token1, 'IF: INVALID_TO');
if (amount0Out > 0) _safeTransfer(token0, to, amount0Out); // optimistically transfer tokens
if (amount1Out > 0) _safeTransfer(token1, to, amount1Out); // optimistically transfer tokens
if (data.length > 0) IImpossibleCallee(to).ImpossibleCall(msg.sender, amount0Out, amount1Out, data);
balance0 = IERC20(token0).balanceOf(address(this));
balance1 = IERC20(token1).balanceOf(address(this));
// Check bounds
amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
}
require(amount0In > 0 || amount1In > 0, 'IF: INSUFFICIENT_INPUT_AMOUNT');
{
// Avoid stack too deep errors
bool _isXybk = isXybk;
uint256 _tradeFee = uint256(tradeFee);
uint256 balance0Adjusted = balance0.mul(10000).sub(amount0In.mul(_tradeFee)); // tradeFee amt of basis pts
uint256 balance1Adjusted = balance1.mul(10000).sub(amount1In.mul(_tradeFee)); // tradeFee amt of basis pts
if (_isXybk) {
// Check if trade is legal
TradeState _tradeState = tradeState;
require(
(_tradeState == TradeState.SELL_ALL) ||
(_tradeState == TradeState.SELL_TOKEN_0 && amount1Out == 0) ||
(_tradeState == TradeState.SELL_TOKEN_1 && amount0Out == 0),
'IF: TRADE_NOT_ALLOWED'
);
(uint256 boost0, uint256 boost1) = calcBoost(); // dont update boost
uint256 scaledOldK = xybkComputeK(boost0, boost1).mul(10000**2);
require(
xybkCheckK(boost0, boost1, balance0Adjusted, balance1Adjusted, scaledOldK),
'IF: INSUFFICIENT_XYBK_K'
);
} else {
require(
balance0Adjusted.mul(balance1Adjusted) >= _reserve0.mul(_reserve1).mul(10000**2),
'IF: INSUFFICIENT_UNI_K'
);
}
}
_update(balance0, balance1);
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}
/**
@notice Calculates xybk K value
@dev Uses library function, same as router
@param _boost0 boost0 to calculate xybk K with
@param _boost1 boost1 to calculate xybk K with
@return k The k value given these reserves and boost values
*/
function xybkComputeK(uint256 _boost0, uint256 _boost1) internal view returns (uint256 k) {
(uint256 _reserve0, uint256 _reserve1) = getReserves();
uint256 boost = (_reserve0 > _reserve1) ? _boost0.sub(1) : _boost1.sub(1);
uint256 denom = boost.mul(2).add(1); // 1+2*boost
uint256 term = boost.mul(_reserve0.add(_reserve1)).div(denom.mul(2)); // boost*(x+y)/(2+4*boost)
k = (Math.sqrt(term**2 + _reserve0.mul(_reserve1).div(denom)) + term)**2;
}
/**
@notice Performing K invariant check through an approximation from old K
@dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
@dev If K_new >= K_old, correctness should still hold
@param boost0 Current boost0 in pair
@param boost1 Current boost1 in pair
@param balance0 Current state of balance0 in pair
@param balance1 Current state of balance1 in pair
@param oldK The pre-swap K value
@return bool Whether the new balances satisfy the K check for xybk
*/
function xybkCheckK(
uint256 boost0,
uint256 boost1,
uint256 balance0,
uint256 balance1,
uint256 oldK
) internal pure returns (bool) {
uint256 oldSqrtK = Math.sqrt(oldK);
uint256 boost = (balance0 > balance1) ? boost0.sub(1) : boost1.sub(1);
uint256 innerTerm = boost.mul(oldSqrtK);
return (balance0.add(innerTerm)).mul(balance1.add(innerTerm)).div((boost.add(1))**2) >= oldK;
}
/**
@notice Forces balances to match reserves
@dev Requires balance0 >= reserve0 and balance1 >= reserve1
@param to Address to send excess underlying tokens to
*/
function skim(address to) external override nonReentrant {
address _token0 = token0; // gas savings
address _token1 = token1; // gas savings
(uint256 _reserve0, uint256 _reserve1) = getReserves();
_safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(_reserve0));
_safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(_reserve1));
}
/**
@notice Forces reserves to match balances
*/
function sync() external override nonReentrant {
uint256 _balance0 = IERC20(token0).balanceOf(address(this));
uint256 _balance1 = IERC20(token1).balanceOf(address(this));
_update(_balance0, _balance1);
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
// a library for performing various math operations
library Math {
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? x : y;
}
// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, 'ReentrancyGuard: reentrant call');
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './IImpossibleERC20.sol';
interface IImpossiblePair is IImpossibleERC20 {
enum TradeState {
SELL_ALL,
SELL_TOKEN_0,
SELL_TOKEN_1,
SELL_NONE
}
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(uint256 reserve0, uint256 reserve1);
event ChangeInvariant(bool _isXybk, uint256 _newBoost0, uint256 _newBoost1);
event UpdatedTradeFees(uint256 _oldFee, uint256 _newFee);
event UpdatedDelay(uint256 _oldDelay, uint256 _newDelay);
event UpdatedTradeState(TradeState _tradeState);
event UpdatedWithdrawalFeeRatio(uint256 _oldWithdrawalFee, uint256 _newWithdrawalFee);
event UpdatedBoost(
uint32 _oldBoost0,
uint32 _oldBoost1,
uint32 _newBoost0,
uint32 _newBoost1,
uint256 _start,
uint256 _end
);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address); // address of token0
function token1() external view returns (address); // address of token1
function getReserves() external view returns (uint256, uint256); // reserves of token0/token1
function calcBoost() external view returns (uint256, uint256);
function mint(address) external returns (uint256);
function burn(address) external returns (uint256, uint256);
function swap(
uint256,
uint256,
address,
bytes calldata
) external;
function skim(address to) external;
function sync() external;
function getPairSettings()
external
view
returns (
uint16,
TradeState,
bool
); // Uses single storage slot, save gas
function delay() external view returns (uint256); // Amount of time delay required before any change to boost etc, denoted in seconds
function initialize(
address,
address,
address,
address
) external;
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
interface IImpossibleSwapFactory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
event UpdatedGovernance(address governance);
function feeTo() external view returns (address);
function governance() 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 setGovernance(address) external;
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
interface IImpossibleCallee {
function ImpossibleCall(
address sender,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './ImpossiblePair.sol';
import './ImpossibleWrappedToken.sol';
import './interfaces/IImpossibleSwapFactory.sol';
/**
@title Swap Factory for Impossible Swap V3
@author Impossible Finance
@notice This factory builds upon basic Uni V2 factory by changing "feeToSetter"
to "governance" and adding a whitelist
@dev See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/
contract ImpossibleSwapFactory is IImpossibleSwapFactory {
address public override feeTo;
address public override governance;
address public router;
address public routerExtension;
bool public whitelist;
mapping(address => bool) public approvedTokens;
mapping(address => mapping(address => address)) public override getPair;
address[] public override allPairs;
/**
@notice The constructor for the IF swap factory
@param _governance The address for IF Governance
*/
constructor(address _governance) {
governance = _governance;
}
modifier onlyGovernance() {
require(msg.sender == governance, 'IF: FORBIDDEN');
_;
}
/**
@notice The constructor for the IF swap factory
@dev _governance The address for IF Governance
@return uint256 The current number of pairs in the IF swap
*/
function allPairsLength() external view override returns (uint256) {
return allPairs.length;
}
/**
@notice Sets router address in factory
@dev Router is checked in pair contracts to ensure calls are from IF routers only
@dev Can only be set by IF governance
@param _router The address of the IF router
@param _routerExtension The address of the IF router extension
*/
function setRouterAndExtension(address _router, address _routerExtension) external onlyGovernance {
router = _router;
routerExtension = _routerExtension;
}
/**
@notice Either allow or stop a token from being a valid token for new pair contracts
@dev Changes can only be made by IF governance
@param token The address of the token
@param allowed The boolean to include/exclude this token in the whitelist
*/
function changeTokenAccess(address token, bool allowed) external onlyGovernance {
approvedTokens[token] = allowed;
}
/**
@notice Turns on or turns off the whitelist feature
@dev Can only be set by IF governance
@param b The boolean that whitelist is set to
*/
function setWhitelist(bool b) external onlyGovernance {
whitelist = b;
}
/**
@notice Creates a new Impossible Pair contract
@dev If whitelist is on, can only use approved tokens in whitelist
@dev tokenA must not be equal to tokenB
@param tokenA The address of token A. Token A will be in the new Pair contract
@param tokenB The address of token B. Token B will be in the new Pair contract
@return pair The address of the created pair containing token A and token B
*/
function createPair(address tokenA, address tokenB) external override returns (address pair) {
if (whitelist) {
require(approvedTokens[tokenA] && approvedTokens[tokenB], 'IF: RESTRICTED_TOKENS');
}
require(tokenA != tokenB, 'IF: IDENTICAL_ADDRESSES');
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'IF: ZERO_ADDRESS');
require(getPair[token0][token1] == address(0), 'IF: PAIR_EXISTS');
bytes memory bytecode = type(ImpossiblePair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
IImpossiblePair(pair).initialize(token0, token1, router, routerExtension);
getPair[token0][token1] = pair;
getPair[token1][token0] = pair;
allPairs.push(pair);
emit PairCreated(token0, token1, pair, allPairs.length);
}
/**
@notice Sets the address that fees from the swap are paid to
@dev Can only be called by IF governance
@param _feeTo The address that will receive swap fees
*/
function setFeeTo(address _feeTo) external override onlyGovernance {
feeTo = _feeTo;
}
/**
@notice Sets the address for IF governance
@dev Can only be called by IF governance
@param _governance The address of the new IF governance
*/
function setGovernance(address _governance) external override onlyGovernance {
governance = _governance;
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './libraries/TransferHelper.sol';
import './libraries/SafeMath.sol';
import './libraries/ReentrancyGuard.sol';
import './interfaces/IImpossibleWrappedToken.sol';
import './interfaces/IERC20.sol';
contract ImpossibleWrappedToken is IImpossibleWrappedToken, ReentrancyGuard {
using SafeMath for uint256;
string public override name;
string public override symbol;
uint8 public override decimals = 18;
uint256 public override totalSupply;
IERC20 public underlying;
uint256 public underlyingBalance;
uint256 public ratioNum;
uint256 public ratioDenom;
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
constructor(
address _underlying,
uint256 _ratioNum,
uint256 _ratioDenom
) {
underlying = IERC20(_underlying);
ratioNum = _ratioNum;
ratioDenom = _ratioDenom;
string memory desc = string(abi.encodePacked(underlying.symbol()));
name = string(abi.encodePacked('IF-Wrapped ', desc));
symbol = string(abi.encodePacked('WIF ', desc));
}
// amt = amount of wrapped tokens
function deposit(address dst, uint256 sendAmt) public override nonReentrant returns (uint256 wad) {
TransferHelper.safeTransferFrom(address(underlying), msg.sender, address(this), sendAmt);
uint256 receiveAmt = IERC20(underlying).balanceOf(address(this)).sub(underlyingBalance);
wad = receiveAmt.mul(ratioNum).div(ratioDenom);
balanceOf[dst] = balanceOf[dst].add(wad);
totalSupply = totalSupply.add(wad);
underlyingBalance = underlyingBalance.add(receiveAmt);
emit Transfer(address(0), dst, wad);
}
// wad = amount of wrapped tokens
function withdraw(address dst, uint256 wad) public override nonReentrant returns (uint256 transferAmt) {
balanceOf[msg.sender] = balanceOf[msg.sender].sub(wad);
totalSupply = totalSupply.sub(wad);
transferAmt = wad.mul(ratioDenom).div(ratioNum);
TransferHelper.safeTransfer(address(underlying), dst, transferAmt);
underlyingBalance = underlyingBalance.sub(transferAmt);
emit Transfer(msg.sender, address(0), wad);
}
function amtToUnderlyingAmt(uint256 amt) public view override returns (uint256) {
return amt.mul(ratioDenom).div(ratioNum);
}
function approve(address guy, uint256 wad) public override returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint256 wad) public override returns (bool) {
require(dst != address(0x0), 'IF Wrapper: INVALID_DST');
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(
address src,
address dst,
uint256 wad
) public override returns (bool) {
require(balanceOf[src] >= wad, '');
require(dst != address(0x0), 'IF Wrapper: INVALID_DST');
if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) {
require(allowance[src][msg.sender] >= wad, 'ImpossibleWrapper: INSUFF_ALLOWANCE');
allowance[src][msg.sender] -= wad;
}
balanceOf[src] -= wad;
balanceOf[dst] += wad;
emit Transfer(src, dst, wad);
return true;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.0;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 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))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 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))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 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))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './IERC20.sol';
interface IImpossibleWrappedToken is IERC20 {
function deposit(address, uint256) external returns (uint256);
function withdraw(address, uint256) external returns (uint256);
function amtToUnderlyingAmt(uint256) external returns (uint256);
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './interfaces/IImpossiblePair.sol';
import './interfaces/IImpossibleSwapFactory.sol';
import './interfaces/IImpossibleRouterExtension.sol';
import './libraries/ImpossibleLibrary.sol';
contract ImpossibleRouterExtension is IImpossibleRouterExtension {
address public immutable override factory;
constructor(address _factory) {
factory = _factory;
}
/**
@notice Helper function for basic swap
@dev Requires the initial amount to have been sent to the first pair contract
@param amounts[] An array of trade amounts. Trades are made from arr idx 0 to arr end idx sequentially
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
*/
function swap(uint256[] memory amounts, address[] memory path) public override {
for (uint256 i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0, ) = ImpossibleLibrary.sortTokens(input, output);
uint256 amountOut = amounts[i + 1];
(uint256 amount0Out, uint256 amount1Out) = input == token0
? (uint256(0), amountOut)
: (amountOut, uint256(0));
address to = i < path.length - 2 ? ImpossibleLibrary.pairFor(factory, output, path[i + 2]) : msg.sender;
IImpossiblePair(ImpossibleLibrary.pairFor(factory, input, output)).swap(
amount0Out,
amount1Out,
to,
new bytes(0)
);
}
}
/**
@notice Helper function for swap supporting fee on transfer tokens
@dev Requires the initial amount to have been sent to the first pair contract
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
*/
function swapSupportingFeeOnTransferTokens(address[] memory path) public override {
for (uint256 i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(uint256 amount0Out, uint256 amount1Out) = ImpossibleLibrary.getAmountOutFeeOnTransfer(
input,
output,
factory
);
address to = i < path.length - 2 ? ImpossibleLibrary.pairFor(factory, output, path[i + 2]) : msg.sender;
IImpossiblePair(ImpossibleLibrary.pairFor(factory, input, output)).swap(
amount0Out,
amount1Out,
to,
new bytes(0)
);
}
}
/**
@notice Helper function for adding liquidity
@dev Logic is unchanged from uniswap-V2-Router02
@param tokenA The address of underlying tokenA to add
@param tokenB The address of underlying tokenB to add
@param amountADesired The desired amount of tokenA to add
@param amountBDesired The desired amount of tokenB to add
@param amountAMin The min amount of tokenA to add (amountAMin:amountBDesired sets bounds on ratio)
@param amountBMin The min amount of tokenB to add (amountADesired:amountBMin sets bounds on ratio)
@return amountA Actual amount of tokenA added as liquidity to pair
@return amountB Actual amount of tokenB added as liquidity to pair
*/
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin
) public override returns (uint256 amountA, uint256 amountB) {
// create the pair if it doesn't exist yet
if (IImpossibleSwapFactory(factory).getPair(tokenA, tokenB) == address(0)) {
IImpossibleSwapFactory(factory).createPair(tokenA, tokenB);
}
(uint256 reserveA, uint256 reserveB, ) = ImpossibleLibrary.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else if (reserveA == 0) {
amountB = amountBDesired;
} else if (reserveB == 0) {
amountA = amountADesired;
} else {
uint256 amountBOptimal = ImpossibleLibrary.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'ImpossibleRouter: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint256 amountAOptimal = ImpossibleLibrary.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'ImpossibleRouter: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
/**
@notice Helper function for removing liquidity
@dev Logic is unchanged from uniswap-V2-Router02
@param tokenA The address of underlying tokenA in LP token
@param tokenB The address of underlying tokenB in LP token
@param pair The address of the pair corresponding to tokenA and tokenB
@param amountAMin The min amount of underlying tokenA that has to be received
@param amountBMin The min amount of underlying tokenB that has to be received
@return amountA Actual amount of underlying tokenA received
@return amountB Actual amount of underlying tokenB received
*/
function removeLiquidity(
address tokenA,
address tokenB,
address pair,
uint256 amountAMin,
uint256 amountBMin
) public override returns (uint256 amountA, uint256 amountB) {
(uint256 amount0, uint256 amount1) = IImpossiblePair(pair).burn(msg.sender);
(address token0, ) = ImpossibleLibrary.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'ImpossibleRouter: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'ImpossibleRouter: INSUFFICIENT_B_AMOUNT');
}
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) public pure virtual override returns (uint256 amountB) {
return ImpossibleLibrary.quote(amountA, reserveA, reserveB);
}
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut
) public view virtual override returns (uint256 amountOut) {
return ImpossibleLibrary.getAmountOut(amountIn, tokenIn, tokenOut, factory);
}
function getAmountIn(
uint256 amountOut,
address tokenIn,
address tokenOut
) public view virtual override returns (uint256 amountIn) {
return ImpossibleLibrary.getAmountIn(amountOut, tokenIn, tokenOut, factory);
}
function getAmountsOut(uint256 amountIn, address[] memory path)
public
view
virtual
override
returns (uint256[] memory amounts)
{
return ImpossibleLibrary.getAmountsOut(factory, amountIn, path);
}
function getAmountsIn(uint256 amountOut, address[] memory path)
public
view
virtual
override
returns (uint256[] memory amounts)
{
return ImpossibleLibrary.getAmountsIn(factory, amountOut, path);
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './IImpossiblePair.sol';
interface IImpossibleRouterExtension {
function factory() external returns (address factoryAddr);
function swap(uint256[] memory amounts, address[] memory path) external;
function swapSupportingFeeOnTransferTokens(address[] memory path) external;
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidity(
address tokenA,
address tokenB,
address pair,
uint256 amountAMin,
uint256 amountBMin
) external returns (uint256 amountA, uint256 amountB);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut
) external view returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
address tokenIn,
address tokenOut
) external view returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);
}/// SPDX-License-Identifier: GPL-3
pragma solidity >=0.5.0;
import '../interfaces/IImpossiblePair.sol';
import '../interfaces/IERC20.sol';
import './SafeMath.sol';
import './Math.sol';
library ImpossibleLibrary {
using SafeMath for uint256;
/**
@notice Sorts tokens in ascending order
@param tokenA The address of token A
@param tokenB The address of token B
@return token0 The address of token 0 (lexicographically smaller than addr of token 1)
@return token1 The address of token 1 (lexicographically larger than addr of token 0)
*/
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'ImpossibleLibrary: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'ImpossibleLibrary: ZERO_ADDRESS');
}
/**
@notice Computes the pair contract create2 address deterministically
@param factory The address of the token factory (pair contract deployer)
@param tokenA The address of token A
@param tokenB The address of token B
@return pair The address of the pair containing token A and B
*/
function pairFor(
address factory,
address tokenA,
address tokenB
) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'fc84b622ba228c468b74c2d99bfe9454ffac280ac017f05a02feb9f739aeb1e4' // init code hash
)
)
)
);
}
/**
@notice Obtains the token reserves in the pair contract
@param factory The address of the token factory (pair contract deployer)
@param tokenA The address of token A
@param tokenB The address of token B
@return reserveA The amount of token A in reserves
@return reserveB The amount of token B in reserves
@return pair The address of the pair containing token A and B
*/
function getReserves(
address factory,
address tokenA,
address tokenB
)
internal
view
returns (
uint256 reserveA,
uint256 reserveB,
address pair
)
{
(address token0, ) = sortTokens(tokenA, tokenB);
pair = pairFor(factory, tokenA, tokenB);
(uint256 reserve0, uint256 reserve1) = IImpossiblePair(pair).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
/**
@notice Quote returns amountB based on some amountA, in the ratio of reserveA:reserveB
@param amountA The amount of token A
@param reserveA The amount of reserveA
@param reserveB The amount of reserveB
@return amountB The amount of token B that matches amount A in the ratio of reserves
*/
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 amountB) {
require(amountA > 0, 'ImpossibleLibrary: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'ImpossibleLibrary: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
/**
@notice Internal function to compute the K value for an xybk pair based on token balances and boost
@dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
@dev Implementation is the same as in pair
@param boost0 Current boost0 in pair
@param boost1 Current boost1 in pair
@param balance0 Current state of balance0 in pair
@param balance1 Current state of balance1 in pair
@return k Value of K invariant
*/
function xybkComputeK(
uint256 boost0,
uint256 boost1,
uint256 balance0,
uint256 balance1
) internal pure returns (uint256 k) {
uint256 boost = (balance0 > balance1) ? boost0.sub(1) : boost1.sub(1);
uint256 denom = boost.mul(2).add(1); // 1+2*boost
uint256 term = boost.mul(balance0.add(balance1)).div(denom.mul(2)); // boost*(x+y)/(2+4*boost)
k = (Math.sqrt(term**2 + balance0.mul(balance1).div(denom)) + term)**2;
}
/**
@notice Internal helper function for calculating artificial liquidity
@dev More details on math at: https://docs.impossible.finance/impossible-swap/swap-math
@param _boost The boost variable on the correct side for the pair contract
@param _sqrtK The sqrt of the invariant variable K in xybk formula
@return uint256 The artificial liquidity term
*/
function calcArtiLiquidityTerm(uint256 _boost, uint256 _sqrtK) internal pure returns (uint256) {
return (_boost - 1).mul(_sqrtK);
}
/**
@notice Quotes maximum output given exact input amount of tokens and addresses of tokens in pair
@dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
@dev However, library function doesn't consider limits created by hardstops
@param amountIn The input amount of token A
@param tokenIn The address of input token
@param tokenOut The address of output token
@param factory The address of the factory contract
@return amountOut The maximum output amount of token B for a valid swap
*/
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut,
address factory
) internal view returns (uint256 amountOut) {
require(amountIn > 0, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');
uint256 reserveIn;
uint256 reserveOut;
uint256 amountInPostFee;
address pair;
bool isMatch;
{
// Avoid stack too deep
(address token0, ) = sortTokens(tokenIn, tokenOut);
isMatch = tokenIn == token0;
(reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut);
}
uint256 artiLiqTerm;
bool isXybk;
{
// Avoid stack too deep
uint256 fee;
IImpossiblePair.TradeState tradeState;
(fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
amountInPostFee = amountIn.mul(10000 - fee);
require(
(tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
'ImpossibleLibrary: TRADE_NOT_ALLOWED'
);
}
/// If xybk invariant, set reserveIn/reserveOut to artificial liquidity instead of actual liquidity
if (isXybk) {
(uint256 boost0, uint256 boost1) = IImpossiblePair(pair).calcBoost();
uint256 sqrtK = Math.sqrt(
xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
);
/// since balance0=balance1 only at sqrtK, if final balanceIn >= sqrtK means balanceIn >= balanceOut
/// Use post-fee balances to maintain consistency with pair contract K invariant check
if (amountInPostFee.add(reserveIn.mul(10000)) >= sqrtK.mul(10000)) {
/// If tokenIn = token0, balanceIn > sqrtK => balance0>sqrtK, use boost0
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
/// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
/// Don't need to check in other case for reserveIn < reserveIn.add(x) <= sqrtK since that case doesnt cross midpt
if (reserveIn < sqrtK && boost0 != boost1) {
/// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
amountOut = reserveOut.sub(sqrtK);
amountInPostFee = amountInPostFee.sub((sqrtK.sub(reserveIn)).mul(10000));
reserveIn = sqrtK;
reserveOut = sqrtK;
}
} else {
/// If tokenIn = token0, balanceIn < sqrtK => balance0<sqrtK, use boost1
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
}
}
uint256 numerator = amountInPostFee.mul(reserveOut.add(artiLiqTerm));
uint256 denominator = (reserveIn.add(artiLiqTerm)).mul(10000).add(amountInPostFee);
uint256 lastSwapAmountOut = numerator / denominator;
amountOut = (lastSwapAmountOut > reserveOut) ? reserveOut.add(amountOut) : lastSwapAmountOut.add(amountOut);
}
/**
@notice Quotes minimum input given exact output amount of tokens and addresses of tokens in pair
@dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
@dev However, library function doesn't consider limits created by hardstops
@param amountOut The desired output amount of token A
@param tokenIn The address of input token
@param tokenOut The address of output token
@param factory The address of the factory contract
@return amountIn The minimum input amount of token A for a valid swap
*/
function getAmountIn(
uint256 amountOut,
address tokenIn,
address tokenOut,
address factory
) internal view returns (uint256 amountIn) {
require(amountOut > 0, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');
uint256 reserveIn;
uint256 reserveOut;
uint256 artiLiqTerm;
uint256 fee;
bool isMatch;
{
// Avoid stack too deep
bool isXybk;
uint256 boost0;
uint256 boost1;
{
// Avoid stack too deep
(address token0, ) = sortTokens(tokenIn, tokenOut);
isMatch = tokenIn == token0;
}
{
// Avoid stack too deep
address pair;
(reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut);
IImpossiblePair.TradeState tradeState;
(fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
require(
(tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
'ImpossibleLibrary: TRADE_NOT_ALLOWED'
);
(boost0, boost1) = IImpossiblePair(pair).calcBoost();
}
if (isXybk) {
uint256 sqrtK = Math.sqrt(
xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
);
/// since balance0=balance1 only at sqrtK, if final balanceOut >= sqrtK means balanceOut >= balanceIn
if (reserveOut.sub(amountOut) >= sqrtK) {
/// If tokenIn = token0, balanceOut > sqrtK => balance1>sqrtK, use boost1
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
} else {
/// If tokenIn = token0, balanceOut < sqrtK => balance0>sqrtK, use boost0
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
/// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
/// Don't need to check in other case for reserveOut > reserveOut.sub(x) >= sqrtK since that case doesnt cross midpt
if (reserveOut > sqrtK && boost0 != boost1) {
/// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
amountIn = sqrtK.sub(reserveIn).mul(10000); /// Still need to divide by (10000 - fee). Do with below calculation to prevent early truncation
amountOut = amountOut.sub(reserveOut.sub(sqrtK));
reserveOut = sqrtK;
reserveIn = sqrtK;
}
}
}
}
uint256 numerator = (reserveIn.add(artiLiqTerm)).mul(amountOut).mul(10000);
uint256 denominator = (reserveOut.add(artiLiqTerm)).sub(amountOut);
amountIn = (amountIn.add((numerator / denominator)).div(10000 - fee)).add(1);
}
/**
@notice Quotes maximum output given some uncertain input amount of tokens and addresses of tokens in pair
@dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
@dev However, library function doesn't consider limits created by hardstops
@param tokenIn The address of input token
@param tokenOut The address of output token
@param factory The address of the factory contract
@return uint256 The maximum possible output amount of token A
@return uint256 The maximum possible output amount of token B
*/
function getAmountOutFeeOnTransfer(
address tokenIn,
address tokenOut,
address factory
) internal view returns (uint256, uint256) {
uint256 reserveIn;
uint256 reserveOut;
address pair;
bool isMatch;
{
// Avoid stack too deep
(address token0, ) = sortTokens(tokenIn, tokenOut);
isMatch = tokenIn == token0;
(reserveIn, reserveOut, pair) = getReserves(factory, tokenIn, tokenOut); /// Should be reserve0/1 but reuse variables to save stack
}
uint256 amountOut;
uint256 artiLiqTerm;
uint256 amountInPostFee;
bool isXybk;
{
// Avoid stack too deep
uint256 fee;
uint256 balanceIn = IERC20(tokenIn).balanceOf(address(pair));
require(balanceIn > reserveIn, 'ImpossibleLibrary: INSUFFICIENT_INPUT_AMOUNT');
IImpossiblePair.TradeState tradeState;
(fee, tradeState, isXybk) = IImpossiblePair(pair).getPairSettings();
require(
(tradeState == IImpossiblePair.TradeState.SELL_ALL) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_0 && !isMatch) ||
(tradeState == IImpossiblePair.TradeState.SELL_TOKEN_1 && isMatch),
'ImpossibleLibrary: TRADE_NOT_ALLOWED'
);
amountInPostFee = (balanceIn.sub(reserveIn)).mul(10000 - fee);
}
/// If xybk invariant, set reserveIn/reserveOut to artificial liquidity instead of actual liquidity
if (isXybk) {
(uint256 boost0, uint256 boost1) = IImpossiblePair(pair).calcBoost();
uint256 sqrtK = Math.sqrt(
xybkComputeK(boost0, boost1, isMatch ? reserveIn : reserveOut, isMatch ? reserveOut : reserveIn)
);
/// since balance0=balance1 only at sqrtK, if final balanceIn >= sqrtK means balanceIn >= balanceOut
/// Use post-fee balances to maintain consistency with pair contract K invariant check
if (amountInPostFee.add(reserveIn.mul(10000)) >= sqrtK.mul(10000)) {
/// If tokenIn = token0, balanceIn > sqrtK => balance0>sqrtK, use boost0
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost0 : boost1, sqrtK);
/// If balance started from <sqrtK and ended at >sqrtK and boosts are different, there'll be different amountIn/Out
/// Don't need to check in other case for reserveIn < reserveIn.add(x) <= sqrtK since that case doesnt cross midpt
if (reserveIn < sqrtK && boost0 != boost1) {
/// Break into 2 trades => start point -> midpoint (sqrtK, sqrtK), then midpoint -> final point
amountOut = reserveOut.sub(sqrtK);
amountInPostFee = amountInPostFee.sub(sqrtK.sub(reserveIn));
reserveOut = sqrtK;
reserveIn = sqrtK;
}
} else {
/// If tokenIn = token0, balanceIn < sqrtK => balance0<sqrtK, use boost0
artiLiqTerm = calcArtiLiquidityTerm(isMatch ? boost1 : boost0, sqrtK);
}
}
uint256 numerator = amountInPostFee.mul(reserveOut.add(artiLiqTerm));
uint256 denominator = (reserveIn.add(artiLiqTerm)).mul(10000).add(amountInPostFee);
uint256 lastSwapAmountOut = numerator / denominator;
amountOut = (lastSwapAmountOut > reserveOut) ? reserveOut.add(amountOut) : lastSwapAmountOut.add(amountOut);
return isMatch ? (uint256(0), amountOut) : (amountOut, uint256(0));
}
/**
@notice Quotes maximum output given exact input amount of tokens and addresses of tokens in trade sequence
@dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
@dev However, library function doesn't consider limits created by hardstops
@param factory The address of the IF factory
@param amountIn The input amount of token A
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@return amounts The maximum possible output amount of all tokens through sequential swaps
*/
function getAmountsOut(
address factory,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'ImpossibleLibrary: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i; i < path.length - 1; i++) {
amounts[i + 1] = getAmountOut(amounts[i], path[i], path[i + 1], factory);
}
}
/**
@notice Quotes minimum input given exact output amount of tokens and addresses of tokens in trade sequence
@dev The library function considers custom swap fees/invariants/asymmetric tuning of pairs
@dev However, library function doesn't consider limits created by hardstops
@param factory The address of the IF factory
@param amountOut The output amount of token A
@param path[] An array of token addresses. Trades are made from arr idx 0 to arr end idx sequentially
@return amounts The minimum output amount required of all tokens through sequential swaps
*/
function getAmountsIn(
address factory,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, 'ImpossibleLibrary: INVALID_PATH');
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
amounts[i - 1] = getAmountIn(amounts[i], path[i - 1], path[i], factory);
}
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import '../libraries/SafeMath.sol';
contract DeflatingERC20 {
using SafeMath for uint256;
string public constant name = 'Deflating Test Token';
string public constant symbol = 'DTT';
uint8 public constant decimals = 18;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public nonces;
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(uint256 _totalSupply) {
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
_mint(msg.sender, _totalSupply);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
uint256 burnAmount = value / 100;
_burn(from, burnAmount);
uint256 transferAmount = value.sub(burnAmount);
balanceOf[from] = balanceOf[from].sub(transferAmount);
balanceOf[to] = balanceOf[to].add(transferAmount);
emit Transfer(from, to, transferAmount);
}
function approve(address spender, uint256 value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, 'EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
import './ImpossibleWrappedToken.sol';
import './interfaces/IImpossibleWrapperFactory.sol';
import './interfaces/IERC20.sol';
/**
@title Wrapper Factory for Impossible Swap V3
@author Impossible Finance
@notice This factory builds upon basic Uni V2 factory by changing "feeToSetter"
to "governance" and adding a whitelist
@dev See documentation at: https://docs.impossible.finance/impossible-swap/overview
*/
contract ImpossibleWrapperFactory is IImpossibleWrapperFactory {
address public governance;
mapping(address => address) public override tokensToWrappedTokens;
mapping(address => address) public override wrappedTokensToTokens;
/**
@notice The constructor for the IF swap factory
@param _governance The address for IF Governance
*/
constructor(address _governance) {
governance = _governance;
}
modifier onlyGovernance() {
require(msg.sender == governance, 'IF: FORBIDDEN');
_;
}
/**
@notice Sets the address for IF governance
@dev Can only be called by IF governance
@param _governance The address of the new IF governance
*/
function setGovernance(address _governance) external onlyGovernance {
governance = _governance;
}
/**
@notice Creates a pair with some ratio
@dev underlying The address of token to wrap
@dev ratioNumerator The numerator value of the ratio to apply for ratio * underlying = wrapped underlying
@dev ratioDenominator The denominator value of the ratio to apply for ratio * underlying = wrapped underlying
*/
function createPairing(
address underlying,
uint256 ratioNumerator,
uint256 ratioDenominator
) external onlyGovernance returns (address) {
require(
tokensToWrappedTokens[underlying] == address(0x0) && wrappedTokensToTokens[underlying] == address(0x0),
'IF: PAIR_EXISTS'
);
require(ratioNumerator != 0 && ratioDenominator != 0, 'IF: INVALID_RATIO');
ImpossibleWrappedToken wrapper = new ImpossibleWrappedToken(underlying, ratioNumerator, ratioDenominator);
tokensToWrappedTokens[underlying] = address(wrapper);
wrappedTokensToTokens[address(wrapper)] = underlying;
emit WrapCreated(underlying, address(wrapper), ratioNumerator, ratioDenominator);
return address(wrapper);
}
/**
@notice Deletes a pairing
@notice requires supply of wrapped token to be 0
@dev wrapper The address of the wrapper
*/
function deletePairing(address wrapper) external onlyGovernance {
require(ImpossibleWrappedToken(wrapper).totalSupply() == 0, 'IF: NONZERO_SUPPLY');
address _underlying = wrappedTokensToTokens[wrapper];
require(ImpossibleWrappedToken(wrapper).underlying() == IERC20(_underlying), 'IF: INVALID_TOKEN');
require(_underlying != address(0x0), 'IF: Address must have pair');
delete tokensToWrappedTokens[_underlying];
delete wrappedTokensToTokens[wrapper];
emit WrapDeleted(_underlying, address(wrapper));
}
}// SPDX-License-Identifier: GPL-3
pragma solidity =0.7.6;
interface IImpossibleWrapperFactory {
event WrapCreated(address, address, uint256, uint256);
event WrapDeleted(address, address);
function tokensToWrappedTokens(address) external view returns (address);
function wrappedTokensToTokens(address) external view returns (address);
}// SPDX-License-Identifier: GPL-3
pragma solidity >=0.6.2;
interface IImpossibleRouter {
function factory() external view returns (address factoryAddr);
function routerExtension() external view returns (address routerExtensionAddr);
function wrapFactory() external view returns (address wrapFactoryAddr);
function WETH() external view returns (address WETHAddr);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
}// SPDX-License-Identifier: GPL-3
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_pairFactory","type":"address"},{"internalType":"address","name":"_wrapFactory","type":"address"},{"internalType":"address","name":"_utilitySettingAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"routerExtension","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"address","name":"_routerExtension","type":"address"}],"name":"setUtilities","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"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":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"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":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"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":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"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":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"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":"address[]","name":"path","type":"address[]"},{"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":[],"name":"wrapFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c06040523480156200001157600080fd5b5060405162004a8238038062004a82833981016040819052620000349162000096565b60016000819055606093841b6001600160601b03199081166080529290931b90911660a05281546001600160a01b0319166001600160a01b03909116179055620000df565b80516001600160a01b03811681146200009157600080fd5b919050565b600080600060608486031215620000ab578283fd5b620000b68462000079565b9250620000c66020850162000079565b9150620000d66040850162000079565b90509250925092565b60805160601c60a05160601c61491062000172600039806104085280612a625280612dda5250806104ad528061074b528061080852806109a85280610ae95280610d035280610daf5280610f1852806113e452806114fd52806116b1528061186f5280611bf85280611e675280611fce528061200052806121db52806123c552806126eb528061280152506149106000f3fe6080604052600436106101395760003560e01c80638803dbee116100ab578063c45a01551161006f578063c45a01551461035c578063ded9382a14610371578063e8e3370014610391578063f305d719146103c0578063fa7de13b146103d3578063fb3bdb41146103f357610154565b80638803dbee146102d4578063ad5c4648146102f4578063af2979eb14610309578063b6f9de9514610329578063baa2abde1461033c57610154565b80634a25d94a116100fd5780634a25d94a1461021f578063590c61f01461023f5780635b0d5984146102545780635c11d79514610281578063791ac947146102a15780637ff36ab5146102c157610154565b8063017e2d551461015957806302751cec1461018457806318cbafe5146101b25780632195995c146101df57806338ed1739146101ff57610154565b36610154576003546001600160a01b0316331461015257fe5b005b600080fd5b34801561016557600080fd5b5061016e610406565b60405161017b91906144b8565b60405180910390f35b34801561019057600080fd5b506101a461019f366004614222565b61042a565b60405161017b92919061473d565b3480156101be57600080fd5b506101d26101cd3660046143d0565b610681565b60405161017b91906145d0565b3480156101eb57600080fd5b506101a46101fa3660046140fe565b61099e565b34801561020b57600080fd5b506101d261021a3660046143d0565b610a73565b34801561022b57600080fd5b506101d261023a3660046143d0565b610c39565b34801561024b57600080fd5b5061016e610d92565b34801561026057600080fd5b5061027461026f36600461427f565b610da1565b60405161017b9190614734565b34801561028d57600080fd5b5061015261029c3660046143d0565b610e7e565b3480156102ad57600080fd5b506101526102bc3660046143d0565b6110d4565b6101d26102cf366004614348565b61131c565b3480156102e057600080fd5b506101d26102ef3660046143d0565b61163b565b34801561030057600080fd5b5061016e6117e7565b34801561031557600080fd5b50610274610324366004614222565b6117f6565b610152610337366004614348565b611abd565b34801561034857600080fd5b506101a461035736600461408d565b611df1565b34801561036857600080fd5b5061016e611fcc565b34801561037d57600080fd5b506101a461038c36600461427f565b611ff0565b34801561039d57600080fd5b506103b16103ac3660046141a7565b6120d3565b60405161017b9392919061474b565b6103b16103ce366004614222565b6122b3565b3480156103df57600080fd5b506101526103ee366004614055565b6125a0565b6101d2610401366004614348565b612623565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008082428110156104575760405162461bcd60e51b815260040161044e906146fd565b60405180910390fd5b6002600054141561049d576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546104dd907f0000000000000000000000000000000000000000000000000000000000000000908c906001600160a01b0316612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd9061051090339085908e9060040161450d565b602060405180830381600087803b15801561052a57600080fd5b505af115801561053e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105629190614314565b5060025460035460405163e54dc2d760e01b81526001600160a01b039283169263e54dc2d7926105a0928f929091169086908e908e90600401614531565b6040805180830381600087803b1580156105b957600080fd5b505af11580156105cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f191906143ad565b90945092506106018a8786612a48565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90610631908690600401614734565b600060405180830381600087803b15801561064b57600080fd5b505af115801561065f573d6000803e3d6000fd5b5050505061066d8684612b8f565b505060016000559097909650945050505050565b606081428110156106a45760405162461bcd60e51b815260040161044e906146fd565b600260005414156106ea576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03168686600019810181811061070b57fe5b9050602002016020810190610720919061401d565b6001600160a01b0316146107465760405162461bcd60e51b815260040161044e906146c6565b6107a47f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b915086826001845103815181106107b757fe5b602002602001015110156107dd5760405162461bcd60e51b815260040161044e9061467a565b61088a868660008181106107ed57fe5b9050602002016020810190610802919061401d565b336108707f00000000000000000000000000000000000000000000000000000000000000008a8a600081811061083457fe5b9050602002016020810190610849919061401d565b8b8b600181811061085657fe5b905060200201602081019061086b919061401d565b612988565b8560008151811061087d57fe5b6020026020010151612dc0565b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906108be9085908a908a906004016145e3565b600060405180830381600087803b1580156108d857600080fd5b505af11580156108ec573d6000803e3d6000fd5b505060035484516001600160a01b039091169250632e1a7d4d91508490600019810190811061091757fe5b60200260200101516040518263ffffffff1660e01b815260040161093b9190614734565b600060405180830381600087803b15801561095557600080fd5b505af1158015610969573d6000803e3d6000fd5b5050505061098e848360018551038151811061098157fe5b6020026020010151612b8f565b5060016000559695505050505050565b60008060006109ce7f00000000000000000000000000000000000000000000000000000000000000008f8f612988565b90506000876109dd578c6109e1565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610a1c903390309086908f908e908e908e906004016144cc565b600060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b50505050610a5d8f8f8f8f8f8f8f611df1565b9350935050509b509b9950505050505050505050565b60608142811015610a965760405162461bcd60e51b815260040161044e906146fd565b60026000541415610adc576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905550610b427f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b91508682600184510381518110610b5557fe5b60200260200101511015610b7b5760405162461bcd60e51b815260040161044e9061467a565b610b8b868660008181106107ed57fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d98490610bbf9085908a908a906004016145e3565b600060405180830381600087803b158015610bd957600080fd5b505af1158015610bed573d6000803e3d6000fd5b5050505061098e868660018989905003818110610c0657fe5b9050602002016020810190610c1b919061401d565b8584600186510381518110610c2c57fe5b6020026020010151612a48565b60608142811015610c5c5760405162461bcd60e51b815260040161044e906146fd565b60026000541415610ca2576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b031686866000198101818110610cc357fe5b9050602002016020810190610cd8919061401d565b6001600160a01b031614610cfe5760405162461bcd60e51b815260040161044e906146c6565b610d5c7f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b91508682600081518110610d6c57fe5b602002602001015111156107dd5760405162461bcd60e51b815260040161044e90614632565b6002546001600160a01b031681565b6003546000908190610ddf907f0000000000000000000000000000000000000000000000000000000000000000908e906001600160a01b0316612988565b9050600086610dee578b610df2565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610e2d903390309086908e908d908d908d906004016144cc565b600060405180830381600087803b158015610e4757600080fd5b505af1158015610e5b573d6000803e3d6000fd5b50505050610e6d8d8d8d8d8d8d6117f6565b9d9c50505050505050505050505050565b8042811015610e9f5760405162461bcd60e51b815260040161044e906146fd565b60026000541415610ee5576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905550610f6c85856000818110610efd57fe5b9050602002016020810190610f12919061401d565b33610f667f000000000000000000000000000000000000000000000000000000000000000089896000818110610f4457fe5b9050602002016020810190610f59919061401d565b8a8a600181811061085657fe5b8a612dc0565b600254604051636fb0847760e01b81526001600160a01b0390911690636fb0847790610f9e90889088906004016145b4565b600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050506000858560018888905003818110610fe457fe5b9050602002016020810190610ff9919061401d565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161102491906144b8565b60206040518083038186803b15801561103c57600080fd5b505afa158015611050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110749190614330565b9050868110156110965760405162461bcd60e51b815260040161044e9061467a565b6110c5868660001981018181106110a957fe5b90506020020160208101906110be919061401d565b8583612a48565b50506001600055505050505050565b80428110156110f55760405162461bcd60e51b815260040161044e906146fd565b6002600054141561113b576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03168585600019810181811061115c57fe5b9050602002016020810190611171919061401d565b6001600160a01b0316146111975760405162461bcd60e51b815260040161044e906146c6565b6111a785856000818110610efd57fe5b600254604051636fb0847760e01b81526001600160a01b0390911690636fb08477906111d990889088906004016145b4565b600060405180830381600087803b1580156111f357600080fd5b505af1158015611207573d6000803e3d6000fd5b50506003546040516370a0823160e01b8152600093506001600160a01b0390911691506370a082319061123e9030906004016144b8565b60206040518083038186803b15801561125657600080fd5b505afa15801561126a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128e9190614330565b9050868110156112b05760405162461bcd60e51b815260040161044e9061467a565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906112e0908490600401614734565b600060405180830381600087803b1580156112fa57600080fd5b505af115801561130e573d6000803e3d6000fd5b505050506110c58482612b8f565b6060814281101561133f5760405162461bcd60e51b815260040161044e906146fd565b60026000541415611385576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b03169087908790816113a457fe5b90506020020160208101906113b9919061401d565b6001600160a01b0316146113df5760405162461bcd60e51b815260040161044e906146c6565b61143d7f000000000000000000000000000000000000000000000000000000000000000034888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b9150868260018451038151811061145057fe5b602002602001015110156114765760405162461bcd60e51b815260040161044e9061467a565b60035482516001600160a01b039091169063d0e30db090849060009061149857fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb915061152790507f00000000000000000000000000000000000000000000000000000000000000008989600081610f4457fe5b8460008151811061153457fe5b60200260200101516040518363ffffffff1660e01b815260040161155992919061459b565b602060405180830381600087803b15801561157357600080fd5b505af1158015611587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ab9190614314565b6115b157fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906115e59085908a908a906004016145e3565b600060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b5050505061162c868660018989905003818110610c0657fe5b50600160005595945050505050565b6060814281101561165e5760405162461bcd60e51b815260040161044e906146fd565b600260005414156116a4576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260008190555061170a7f000000000000000000000000000000000000000000000000000000000000000089888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b9150868260008151811061171a57fe5b602002602001015111156117405760405162461bcd60e51b815260040161044e90614632565b611750868660008181106107ed57fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906117849085908a908a906004016145e3565b600060405180830381600087803b15801561179e57600080fd5b505af11580156117b2573d6000803e3d6000fd5b5050505061098e8686600189899050038181106117cb57fe5b90506020020160208101906117e0919061401d565b858a612a48565b6003546001600160a01b031681565b600081428110156118195760405162461bcd60e51b815260040161044e906146fd565b6002600054141561185f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600090815560035461189f907f0000000000000000000000000000000000000000000000000000000000000000908b906001600160a01b0316612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd906118d290339085908d9060040161450d565b602060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119249190614314565b5060025460035460405163e54dc2d760e01b81526001600160a01b039283169263e54dc2d792611962928e929091169086908d908d90600401614531565b6040805180830381600087803b15801561197b57600080fd5b505af115801561198f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b391906143ad565b6040516370a0823160e01b8152909450611a4091508a9087906001600160a01b038316906370a08231906119eb9030906004016144b8565b60206040518083038186803b158015611a0357600080fd5b505afa158015611a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3b9190614330565b612a48565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90611a70908690600401614734565b600060405180830381600087803b158015611a8a57600080fd5b505af1158015611a9e573d6000803e3d6000fd5b50505050611aac8584612b8f565b505060016000559695505050505050565b8042811015611ade5760405162461bcd60e51b815260040161044e906146fd565b60026000541415611b24576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b0316908690869081611b4357fe5b9050602002016020810190611b58919061401d565b6001600160a01b031614611b7e5760405162461bcd60e51b815260040161044e906146c6565b60035460408051630d0e30db60e41b8152905134926001600160a01b03169163d0e30db091849160048082019260009290919082900301818588803b158015611bc657600080fd5b505af1158015611bda573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb9150611c2290507f00000000000000000000000000000000000000000000000000000000000000008989600081610f4457fe5b836040518363ffffffff1660e01b8152600401611c4092919061459b565b602060405180830381600087803b158015611c5a57600080fd5b505af1158015611c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c929190614314565b611c9857fe5b600254604051636fb0847760e01b81526001600160a01b0390911690636fb0847790611cca90899089906004016145b4565b600060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506000868660018989905003818110611d1057fe5b9050602002016020810190611d25919061401d565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d5091906144b8565b60206040518083038186803b158015611d6857600080fd5b505afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da09190614330565b905087811015611dc25760405162461bcd60e51b815260040161044e9061467a565b6110c587876000198101818110611dd557fe5b9050602002016020810190611dea919061401d565b8683612a48565b6000808242811015611e155760405162461bcd60e51b815260040161044e906146fd565b60026000541415611e5b576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000908155611e8d7f00000000000000000000000000000000000000000000000000000000000000008c8c612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd90611ec090339085908e9060040161450d565b602060405180830381600087803b158015611eda57600080fd5b505af1158015611eee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f129190614314565b5060025460405163e54dc2d760e01b81526001600160a01b039091169063e54dc2d790611f4b908e908e9086908e908e90600401614531565b6040805180830381600087803b158015611f6457600080fd5b505af1158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c91906143ad565b9094509250611fac8b8786612a48565b611fb78a8785612a48565b50506001600055909890975095505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60035460009081908190612030907f0000000000000000000000000000000000000000000000000000000000000000908f906001600160a01b0316612988565b905060008761203f578c612043565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf9061207e903390309086908f908e908e908e906004016144cc565b600060405180830381600087803b15801561209857600080fd5b505af11580156120ac573d6000803e3d6000fd5b505050506120be8e8e8e8e8e8e61042a565b909f909e509c50505050505050505050505050565b600080600083428110156120f95760405162461bcd60e51b815260040161044e906146fd565b6002600054141561213f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905554604051633351733f60e01b81526001600160a01b0390911690633351733f9061217e908f908f908f908f908f908f90600401614565565b6040805180830381600087803b15801561219757600080fd5b505af11580156121ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cf91906143ad565b909450925060006122017f00000000000000000000000000000000000000000000000000000000000000008e8e612988565b905061220f8d338388612dc0565b61221b8c338387612dc0565b6040516335313c2160e11b81526001600160a01b03821690636a62784290612247908a906004016144b8565b602060405180830381600087803b15801561226157600080fd5b505af1158015612275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122999190614330565b925050600160008190555050985098509895505050505050565b600080600083428110156122d95760405162461bcd60e51b815260040161044e906146fd565b6002600054141561231f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905554600354604051633351733f60e01b81526001600160a01b0392831692633351733f92612363928f92909116908e9034908f908f90600401614565565b6040805180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b491906143ad565b60035491955093506000906123f5907f0000000000000000000000000000000000000000000000000000000000000000908d906001600160a01b0316612988565b90506124038b338388612dc0565b600360009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561245357600080fd5b505af1158015612467573d6000803e3d6000fd5b505060035460405163a9059cbb60e01b81526001600160a01b03909116935063a9059cbb925061249e91508490889060040161459b565b602060405180830381600087803b1580156124b857600080fd5b505af11580156124cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f09190614314565b6124f657fe5b6040516335313c2160e11b81526001600160a01b03821690636a62784290612522908a906004016144b8565b602060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125749190614330565b92508334111561258a5761258a33853403612b8f565b5060016000819055505096509650969350505050565b6003546001600160a01b03161580156125c257506002546001600160a01b0316155b6125cb57600080fd5b6001546001600160a01b031633146125f55760405162461bcd60e51b815260040161044e90614613565b600380546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055565b606081428110156126465760405162461bcd60e51b815260040161044e906146fd565b6002600054141561268c576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b03169087908790816126ab57fe5b90506020020160208101906126c0919061401d565b6001600160a01b0316146126e65760405162461bcd60e51b815260040161044e906146c6565b6127447f000000000000000000000000000000000000000000000000000000000000000088888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b9150348260008151811061275457fe5b6020026020010151111561277a5760405162461bcd60e51b815260040161044e90614632565b60035482516001600160a01b039091169063d0e30db090849060009061279c57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156127cf57600080fd5b505af11580156127e3573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb915061282b90507f00000000000000000000000000000000000000000000000000000000000000008989600081610f4457fe5b8460008151811061283857fe5b60200260200101516040518363ffffffff1660e01b815260040161285d92919061459b565b602060405180830381600087803b15801561287757600080fd5b505af115801561288b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128af9190614314565b6128b557fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906128e99085908a908a906004016145e3565b600060405180830381600087803b15801561290357600080fd5b505af1158015612917573d6000803e3d6000fd5b5050505061294c86866001898990500381811061293057fe5b9050602002016020810190612945919061401d565b8589612a48565b8160008151811061295957fe5b602002602001015134111561162c5761162c338360008151811061297957fe5b60200260200101513403612b8f565b600080600061299785856130d5565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501206001600160f81b031960688401529a90941b9093166069840152607d8301989098527ffc84b622ba228c468b74c2d99bfe9454ffac280ac017f05a02feb9f739aeb1e4609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b604051632a4d95e760e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a936579c90612a979087906004016144b8565b60206040518083038186803b158015612aaf57600080fd5b505afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190614039565b90506001600160a01b038116612b0757612b028484846131b3565b612b89565b60405163f3fef3a360e01b81526001600160a01b0385169063f3fef3a390612b35908690869060040161459b565b602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614330565b505b50505050565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b60208310612bdb5780518252601f199092019160209182019101612bbc565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612c3d576040519150601f19603f3d011682016040523d82523d6000602084013e612c42565b606091505b5050905080612c825760405162461bcd60e51b81526004018080602001828103825260348152602001806148056034913960400191505060405180910390fd5b505050565b6060600282511015612ce0576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a20494e56414c49445f5041544800604482015290519081900360640190fd5b815167ffffffffffffffff81118015612cf857600080fd5b50604051908082528060200260200182016040528015612d22578160200160208202803683370190505b5090508281600081518110612d3357fe5b60200260200101818152505060005b6001835103811015612db857612d96828281518110612d5d57fe5b6020026020010151848381518110612d7157fe5b6020026020010151858460010181518110612d8857fe5b6020026020010151886132ff565b828260010181518110612da557fe5b6020908102919091010152600101612d42565b509392505050565b604051632a4d95e760e21b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a936579c90612e0f9088906004016144b8565b60206040518083038186803b158015612e2757600080fd5b505afa158015612e3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5f9190614039565b90506001600160a01b038116612e8057612e7b85858585613668565b612b87565b604051635ac402df60e11b81526000906001600160a01b0387169063b58805be90612eaf908690600401614734565b602060405180830381600087803b158015612ec957600080fd5b505af1158015612edd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f019190614330565b9050612f0f82863084613668565b612f1a8287836137c4565b6040516311f9fbc960e21b81526001600160a01b038716906347e7ef2490612f48908790859060040161459b565b602060405180830381600087803b158015612f6257600080fd5b505af1158015612f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9a9190614330565b50505050505050565b6060600282511015612ffc576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a20494e56414c49445f5041544800604482015290519081900360640190fd5b815167ffffffffffffffff8111801561301457600080fd5b5060405190808252806020026020018201604052801561303e578160200160208202803683370190505b509050828160018351038151811061305257fe5b60209081029190910101528151600019015b8015612db8576130b282828151811061307957fe5b602002602001015184600184038151811061309057fe5b60200260200101518584815181106130a457fe5b602002602001015188613910565b8260018303815181106130c157fe5b602090810291909101015260001901613064565b600080826001600160a01b0316846001600160a01b031614156131295760405162461bcd60e51b81526004018080602001828103825260268152602001806148b56026913960400191505060405180910390fd5b826001600160a01b0316846001600160a01b03161061314957828461314c565b83835b90925090506001600160a01b0382166131ac576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a205a45524f5f4144445245535300604482015290519081900360640190fd5b9250929050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061322f5780518252601f199092019160209182019101613210565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613291576040519150601f19603f3d011682016040523d82523d6000602084013e613296565b606091505b50915091508180156132c45750805115806132c457508080602001905160208110156132c157600080fd5b50515b612b875760405162461bcd60e51b815260040180806020018281038252602d815260200180614888602d913960400191505060405180910390fd5b600080851161333f5760405162461bcd60e51b815260040180806020018281038252602c815260200180614788602c913960400191505060405180910390fd5b6000806000806000806133528a8a6130d5565b509050806001600160a01b03168a6001600160a01b0316149150613377888b8b613c2b565b80955081975082985050505050600080600080856001600160a01b031663e94e3d8d6040518163ffffffff1660e01b815260040160606040518083038186803b1580156133c357600080fd5b505afa1580156133d7573d6000803e3d6000fd5b505050506040513d60608110156133ed57600080fd5b5080516020820151604090920151945061ffff16925090506134148e612710849003613ced565b9650600081600381111561342457fe5b14806134445750600181600381111561343957fe5b148015613444575084155b806134625750600281600381111561345857fe5b1480156134625750845b61349d5760405162461bcd60e51b81526004018080602001828103825260248152602001806148396024913960400191505060405180910390fd5b505080156135f157600080856001600160a01b031663b6b9f61b6040518163ffffffff1660e01b8152600401604080518083038186803b1580156134e057600080fd5b505afa1580156134f4573d6000803e3d6000fd5b505050506040513d604081101561350a57600080fd5b5080516020909101519092509050600061354661354184848961352d578c61352f565b8d5b8a61353a578e61353c565b8d5b613d56565b613de3565b905061355481612710613ced565b61356a6135638c612710613ced565b8a90613e35565b106135d5576135858661357d578261357f565b835b82613e84565b9450808a1080156135965750818314155b156135d0576135a58982613e9b565b9a506135c76135c06127106135ba848e613e9b565b90613ced565b8990613e9b565b97508099508098505b6135ed565b6135ea866135e3578361357f565b8282613e84565b94505b5050505b60006136076136008885613e35565b8790613ced565b905060006136258761361f6127106135ba8d89613e35565b90613e35565b9050600081838161363257fe5b04905088811161364b57613646818c613e35565b613655565b613655898c613e35565b9f9e505050505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b602083106136ec5780518252601f1990920191602091820191016136cd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461374e576040519150601f19603f3d011682016040523d82523d6000602084013e613753565b606091505b5091509150818015613781575080511580613781575080806020019051602081101561377e57600080fd5b50515b6137bc5760405162461bcd60e51b81526004018080602001828103825260318152602001806147d46031913960400191505060405180910390fd5b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1781529251825160009485949389169392918291908083835b602083106138405780518252601f199092019160209182019101613821565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146138a2576040519150601f19603f3d011682016040523d82523d6000602084013e6138a7565b606091505b50915091508180156138d55750805115806138d557508080602001905160208110156138d257600080fd5b50515b612b875760405162461bcd60e51b815260040180806020018281038252602b81526020018061485d602b913960400191505060405180910390fd5b60008085116139505760405162461bcd60e51b815260040180806020018281038252602c815260200180614788602c913960400191505060405180910390fd5b60008060008060008060008060006139688d8d6130d5565b506001600160a01b038e81169116149450600090506139888b8e8e613c2b565b809350819a50829b505050506000816001600160a01b031663e94e3d8d6040518163ffffffff1660e01b815260040160606040518083038186803b1580156139cf57600080fd5b505afa1580156139e3573d6000803e3d6000fd5b505050506040513d60608110156139f957600080fd5b508051602082015160409092015161ffff9091169850955090506000816003811115613a2157fe5b1480613a4157506001816003811115613a3657fe5b148015613a41575085155b80613a5f57506002816003811115613a5557fe5b148015613a5f5750855b613a9a5760405162461bcd60e51b81526004018080602001828103825260248152602001806148396024913960400191505060405180910390fd5b816001600160a01b031663b6b9f61b6040518163ffffffff1660e01b8152600401604080518083038186803b158015613ad257600080fd5b505afa158015613ae6573d6000803e3d6000fd5b505050506040513d6040811015613afc57600080fd5b50805160209091015190945092505083159050613bc0576000613b3b613541848488613b28578b613b2a565b8c5b89613b35578d61353c565b8c613d56565b905080613b518f8a613e9b90919063ffffffff16565b10613b6b57613b64856135e3578361357f565b9650613bbe565b613b798561357d578261357f565b96508088118015613b8a5750818314155b15613bbe57613b9f6127106135ba838c613e9b565b9950613bb5613bae8983613e9b565b8f90613e9b565b9d508097508098505b505b5060009150613bd990506127106135ba8d818a89613e35565b90506000613bf18c613beb8888613e35565b90613e9b565b9050613c1b600161361f8661271003613c15858781613c0c57fe5b8e919004613e35565b90613eeb565b9c9b505050505050505050505050565b600080600080613c3b86866130d5565b509050613c49878787612988565b9150600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015613c8657600080fd5b505afa158015613c9a573d6000803e3d6000fd5b505050506040513d6040811015613cb057600080fd5b50805160209091015190925090506001600160a01b0388811690841614613cd8578082613cdb565b81815b909a9099509397509295505050505050565b6000811580613d0857505080820282828281613d0557fe5b04145b613d50576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b92915050565b600080828411613d7057613d6b856001613e9b565b613d7b565b613d7b866001613e9b565b90506000613d8f600161361f846002613ced565b90506000613db5613da1836002613ced565b613c15613dae8989613e35565b8690613ced565b9050600281613dd5613dcb85613c158b8b613ced565b6002850a01613de3565b010a98975050505050505050565b60006003821115613e26575080600160028204015b81811015613e2057809150600281828581613e0f57fe5b040181613e1857fe5b049050613df8565b50613e30565b8115613e30575060015b919050565b80820182811015613d50576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b6000613e94600019840183613ced565b9392505050565b80820382811115613d50576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000613e9483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060008183613fb45760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613f79578181015183820152602001613f61565b50505050905090810190601f168015613fa65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613fc057fe5b0495945050505050565b60008083601f840112613fdb578182fd5b50813567ffffffffffffffff811115613ff2578182fd5b60208301915083602080830285010111156131ac57600080fd5b803560ff81168114613e3057600080fd5b60006020828403121561402e578081fd5b8135613e9481614761565b60006020828403121561404a578081fd5b8151613e9481614761565b60008060408385031215614067578081fd5b823561407281614761565b9150602083013561408281614761565b809150509250929050565b600080600080600080600060e0888a0312156140a7578283fd5b87356140b281614761565b965060208801356140c281614761565b955060408801359450606088013593506080880135925060a08801356140e781614761565b8092505060c0880135905092959891949750929550565b60008060008060008060008060008060006101608c8e03121561411f578384fd5b8b3561412a81614761565b9a5060208c013561413a81614761565b995060408c0135985060608c0135975060808c0135965060a08c013561415f81614761565b955060c08c0135945060e08c013561417681614779565b93506141856101008d0161400c565b92506101208c013591506101408c013590509295989b509295989b9093969950565b600080600080600080600080610100898b0312156141c3578384fd5b88356141ce81614761565b975060208901356141de81614761565b965060408901359550606089013594506080890135935060a0890135925060c089013561420a81614761565b8092505060e089013590509295985092959890939650565b60008060008060008060c0878903121561423a578182fd5b863561424581614761565b9550602087013594506040870135935060608701359250608087013561426a81614761565b8092505060a087013590509295509295509295565b6000806000806000806000806000806101408b8d03121561429e578384fd5b8a356142a981614761565b995060208b0135985060408b0135975060608b0135965060808b01356142ce81614761565b955060a08b0135945060c08b01356142e581614779565b93506142f360e08c0161400c565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600060208284031215614325578081fd5b8151613e9481614779565b600060208284031215614341578081fd5b5051919050565b60008060008060006080868803121561435f578283fd5b85359450602086013567ffffffffffffffff81111561437c578384fd5b61438888828901613fca565b909550935050604086013561439c81614761565b949793965091946060013592915050565b600080604083850312156143bf578182fd5b505080516020909101519092909150565b60008060008060008060a087890312156143e8578384fd5b8635955060208701359450604087013567ffffffffffffffff81111561440c578485fd5b61441889828a01613fca565b909550935050606087013561442c81614761565b80925050608087013590509295509295509295565b60008284526020808501945082825b8581101561447e57813561446381614761565b6001600160a01b031687529582019590820190600101614450565b509495945050505050565b6000815180845260208085019450808401835b8381101561447e5781518752958201959082019060010161449c565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b6001600160a01b03929092168252602082015260400190565b6000602082526145c8602083018486614441565b949350505050565b600060208252613e946020830184614489565b6000604082526145f66040830186614489565b8281036020840152614609818587614441565b9695505050505050565b60208082526005908201526449463a203f60d81b604082015260600190565b60208082526028908201527f496d706f737369626c65526f757465723a204558434553534956455f494e50556040820152671517d05353d5539560c21b606082015260800190565b6020808252602c908201527f496d706f737369626c65526f757465723a20494e53554646494349454e545f4f60408201526b155514155517d05353d5539560a21b606082015260800190565b6020808252601e908201527f496d706f737369626c65526f757465723a20494e56414c49445f504154480000604082015260600190565b60208082526019908201527f496d706f737369626c65526f757465723a204558504952454400000000000000604082015260600190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6001600160a01b038116811461477657600080fd5b50565b801515811461477657600080fdfe496d706f737369626c654c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e545265656e7472616e637947756172643a207265656e7472616e742063616c6c005472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472616e7366657246726f6d206661696c65645472616e7366657248656c7065723a3a736166655472616e736665724554483a20455448207472616e73666572206661696c6564496d706f737369626c654c6962726172793a2054524144455f4e4f545f414c4c4f5745445472616e7366657248656c7065723a3a73616665417070726f76653a20617070726f7665206661696c65645472616e7366657248656c7065723a3a736166655472616e736665723a207472616e73666572206661696c6564496d706f737369626c654c6962726172793a204944454e544943414c5f414444524553534553a26469706673582212201d47bb6aa4c4e5a635ca01716e6be81c6af6f3e867a84fc2495526c9765ca44264736f6c6343000706003300000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f50000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e000000000000000000000000554a45ea949851f4b4047ab958a985b4d4884ddd
Deployed Bytecode
0x6080604052600436106101395760003560e01c80638803dbee116100ab578063c45a01551161006f578063c45a01551461035c578063ded9382a14610371578063e8e3370014610391578063f305d719146103c0578063fa7de13b146103d3578063fb3bdb41146103f357610154565b80638803dbee146102d4578063ad5c4648146102f4578063af2979eb14610309578063b6f9de9514610329578063baa2abde1461033c57610154565b80634a25d94a116100fd5780634a25d94a1461021f578063590c61f01461023f5780635b0d5984146102545780635c11d79514610281578063791ac947146102a15780637ff36ab5146102c157610154565b8063017e2d551461015957806302751cec1461018457806318cbafe5146101b25780632195995c146101df57806338ed1739146101ff57610154565b36610154576003546001600160a01b0316331461015257fe5b005b600080fd5b34801561016557600080fd5b5061016e610406565b60405161017b91906144b8565b60405180910390f35b34801561019057600080fd5b506101a461019f366004614222565b61042a565b60405161017b92919061473d565b3480156101be57600080fd5b506101d26101cd3660046143d0565b610681565b60405161017b91906145d0565b3480156101eb57600080fd5b506101a46101fa3660046140fe565b61099e565b34801561020b57600080fd5b506101d261021a3660046143d0565b610a73565b34801561022b57600080fd5b506101d261023a3660046143d0565b610c39565b34801561024b57600080fd5b5061016e610d92565b34801561026057600080fd5b5061027461026f36600461427f565b610da1565b60405161017b9190614734565b34801561028d57600080fd5b5061015261029c3660046143d0565b610e7e565b3480156102ad57600080fd5b506101526102bc3660046143d0565b6110d4565b6101d26102cf366004614348565b61131c565b3480156102e057600080fd5b506101d26102ef3660046143d0565b61163b565b34801561030057600080fd5b5061016e6117e7565b34801561031557600080fd5b50610274610324366004614222565b6117f6565b610152610337366004614348565b611abd565b34801561034857600080fd5b506101a461035736600461408d565b611df1565b34801561036857600080fd5b5061016e611fcc565b34801561037d57600080fd5b506101a461038c36600461427f565b611ff0565b34801561039d57600080fd5b506103b16103ac3660046141a7565b6120d3565b60405161017b9392919061474b565b6103b16103ce366004614222565b6122b3565b3480156103df57600080fd5b506101526103ee366004614055565b6125a0565b6101d2610401366004614348565b612623565b7f0000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e81565b60008082428110156104575760405162461bcd60e51b815260040161044e906146fd565b60405180910390fd5b6002600054141561049d576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546104dd907f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5908c906001600160a01b0316612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd9061051090339085908e9060040161450d565b602060405180830381600087803b15801561052a57600080fd5b505af115801561053e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105629190614314565b5060025460035460405163e54dc2d760e01b81526001600160a01b039283169263e54dc2d7926105a0928f929091169086908e908e90600401614531565b6040805180830381600087803b1580156105b957600080fd5b505af11580156105cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f191906143ad565b90945092506106018a8786612a48565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90610631908690600401614734565b600060405180830381600087803b15801561064b57600080fd5b505af115801561065f573d6000803e3d6000fd5b5050505061066d8684612b8f565b505060016000559097909650945050505050565b606081428110156106a45760405162461bcd60e51b815260040161044e906146fd565b600260005414156106ea576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03168686600019810181811061070b57fe5b9050602002016020810190610720919061401d565b6001600160a01b0316146107465760405162461bcd60e51b815260040161044e906146c6565b6107a47f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f589888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b915086826001845103815181106107b757fe5b602002602001015110156107dd5760405162461bcd60e51b815260040161044e9061467a565b61088a868660008181106107ed57fe5b9050602002016020810190610802919061401d565b336108707f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58a8a600081811061083457fe5b9050602002016020810190610849919061401d565b8b8b600181811061085657fe5b905060200201602081019061086b919061401d565b612988565b8560008151811061087d57fe5b6020026020010151612dc0565b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906108be9085908a908a906004016145e3565b600060405180830381600087803b1580156108d857600080fd5b505af11580156108ec573d6000803e3d6000fd5b505060035484516001600160a01b039091169250632e1a7d4d91508490600019810190811061091757fe5b60200260200101516040518263ffffffff1660e01b815260040161093b9190614734565b600060405180830381600087803b15801561095557600080fd5b505af1158015610969573d6000803e3d6000fd5b5050505061098e848360018551038151811061098157fe5b6020026020010151612b8f565b5060016000559695505050505050565b60008060006109ce7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58f8f612988565b90506000876109dd578c6109e1565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610a1c903390309086908f908e908e908e906004016144cc565b600060405180830381600087803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b50505050610a5d8f8f8f8f8f8f8f611df1565b9350935050509b509b9950505050505050505050565b60608142811015610a965760405162461bcd60e51b815260040161044e906146fd565b60026000541415610adc576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905550610b427f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f589888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b91508682600184510381518110610b5557fe5b60200260200101511015610b7b5760405162461bcd60e51b815260040161044e9061467a565b610b8b868660008181106107ed57fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d98490610bbf9085908a908a906004016145e3565b600060405180830381600087803b158015610bd957600080fd5b505af1158015610bed573d6000803e3d6000fd5b5050505061098e868660018989905003818110610c0657fe5b9050602002016020810190610c1b919061401d565b8584600186510381518110610c2c57fe5b6020026020010151612a48565b60608142811015610c5c5760405162461bcd60e51b815260040161044e906146fd565b60026000541415610ca2576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b031686866000198101818110610cc357fe5b9050602002016020810190610cd8919061401d565b6001600160a01b031614610cfe5760405162461bcd60e51b815260040161044e906146c6565b610d5c7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f589888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b91508682600081518110610d6c57fe5b602002602001015111156107dd5760405162461bcd60e51b815260040161044e90614632565b6002546001600160a01b031681565b6003546000908190610ddf907f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5908e906001600160a01b0316612988565b9050600086610dee578b610df2565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610e2d903390309086908e908d908d908d906004016144cc565b600060405180830381600087803b158015610e4757600080fd5b505af1158015610e5b573d6000803e3d6000fd5b50505050610e6d8d8d8d8d8d8d6117f6565b9d9c50505050505050505050505050565b8042811015610e9f5760405162461bcd60e51b815260040161044e906146fd565b60026000541415610ee5576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905550610f6c85856000818110610efd57fe5b9050602002016020810190610f12919061401d565b33610f667f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f589896000818110610f4457fe5b9050602002016020810190610f59919061401d565b8a8a600181811061085657fe5b8a612dc0565b600254604051636fb0847760e01b81526001600160a01b0390911690636fb0847790610f9e90889088906004016145b4565b600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050506000858560018888905003818110610fe457fe5b9050602002016020810190610ff9919061401d565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161102491906144b8565b60206040518083038186803b15801561103c57600080fd5b505afa158015611050573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110749190614330565b9050868110156110965760405162461bcd60e51b815260040161044e9061467a565b6110c5868660001981018181106110a957fe5b90506020020160208101906110be919061401d565b8583612a48565b50506001600055505050505050565b80428110156110f55760405162461bcd60e51b815260040161044e906146fd565b6002600054141561113b576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03168585600019810181811061115c57fe5b9050602002016020810190611171919061401d565b6001600160a01b0316146111975760405162461bcd60e51b815260040161044e906146c6565b6111a785856000818110610efd57fe5b600254604051636fb0847760e01b81526001600160a01b0390911690636fb08477906111d990889088906004016145b4565b600060405180830381600087803b1580156111f357600080fd5b505af1158015611207573d6000803e3d6000fd5b50506003546040516370a0823160e01b8152600093506001600160a01b0390911691506370a082319061123e9030906004016144b8565b60206040518083038186803b15801561125657600080fd5b505afa15801561126a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128e9190614330565b9050868110156112b05760405162461bcd60e51b815260040161044e9061467a565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906112e0908490600401614734565b600060405180830381600087803b1580156112fa57600080fd5b505af115801561130e573d6000803e3d6000fd5b505050506110c58482612b8f565b6060814281101561133f5760405162461bcd60e51b815260040161044e906146fd565b60026000541415611385576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b03169087908790816113a457fe5b90506020020160208101906113b9919061401d565b6001600160a01b0316146113df5760405162461bcd60e51b815260040161044e906146c6565b61143d7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f534888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612c8792505050565b9150868260018451038151811061145057fe5b602002602001015110156114765760405162461bcd60e51b815260040161044e9061467a565b60035482516001600160a01b039091169063d0e30db090849060009061149857fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156114cb57600080fd5b505af11580156114df573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb915061152790507f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58989600081610f4457fe5b8460008151811061153457fe5b60200260200101516040518363ffffffff1660e01b815260040161155992919061459b565b602060405180830381600087803b15801561157357600080fd5b505af1158015611587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ab9190614314565b6115b157fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906115e59085908a908a906004016145e3565b600060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b5050505061162c868660018989905003818110610c0657fe5b50600160005595945050505050565b6060814281101561165e5760405162461bcd60e51b815260040161044e906146fd565b600260005414156116a4576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260008190555061170a7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f589888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b9150868260008151811061171a57fe5b602002602001015111156117405760405162461bcd60e51b815260040161044e90614632565b611750868660008181106107ed57fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906117849085908a908a906004016145e3565b600060405180830381600087803b15801561179e57600080fd5b505af11580156117b2573d6000803e3d6000fd5b5050505061098e8686600189899050038181106117cb57fe5b90506020020160208101906117e0919061401d565b858a612a48565b6003546001600160a01b031681565b600081428110156118195760405162461bcd60e51b815260040161044e906146fd565b6002600054141561185f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600090815560035461189f907f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5908b906001600160a01b0316612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd906118d290339085908d9060040161450d565b602060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119249190614314565b5060025460035460405163e54dc2d760e01b81526001600160a01b039283169263e54dc2d792611962928e929091169086908d908d90600401614531565b6040805180830381600087803b15801561197b57600080fd5b505af115801561198f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b391906143ad565b6040516370a0823160e01b8152909450611a4091508a9087906001600160a01b038316906370a08231906119eb9030906004016144b8565b60206040518083038186803b158015611a0357600080fd5b505afa158015611a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3b9190614330565b612a48565b600354604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90611a70908690600401614734565b600060405180830381600087803b158015611a8a57600080fd5b505af1158015611a9e573d6000803e3d6000fd5b50505050611aac8584612b8f565b505060016000559695505050505050565b8042811015611ade5760405162461bcd60e51b815260040161044e906146fd565b60026000541415611b24576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b0316908690869081611b4357fe5b9050602002016020810190611b58919061401d565b6001600160a01b031614611b7e5760405162461bcd60e51b815260040161044e906146c6565b60035460408051630d0e30db60e41b8152905134926001600160a01b03169163d0e30db091849160048082019260009290919082900301818588803b158015611bc657600080fd5b505af1158015611bda573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb9150611c2290507f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58989600081610f4457fe5b836040518363ffffffff1660e01b8152600401611c4092919061459b565b602060405180830381600087803b158015611c5a57600080fd5b505af1158015611c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c929190614314565b611c9857fe5b600254604051636fb0847760e01b81526001600160a01b0390911690636fb0847790611cca90899089906004016145b4565b600060405180830381600087803b158015611ce457600080fd5b505af1158015611cf8573d6000803e3d6000fd5b505050506000868660018989905003818110611d1057fe5b9050602002016020810190611d25919061401d565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611d5091906144b8565b60206040518083038186803b158015611d6857600080fd5b505afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da09190614330565b905087811015611dc25760405162461bcd60e51b815260040161044e9061467a565b6110c587876000198101818110611dd557fe5b9050602002016020810190611dea919061401d565b8683612a48565b6000808242811015611e155760405162461bcd60e51b815260040161044e906146fd565b60026000541415611e5b576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b60026000908155611e8d7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58c8c612988565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd90611ec090339085908e9060040161450d565b602060405180830381600087803b158015611eda57600080fd5b505af1158015611eee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f129190614314565b5060025460405163e54dc2d760e01b81526001600160a01b039091169063e54dc2d790611f4b908e908e9086908e908e90600401614531565b6040805180830381600087803b158015611f6457600080fd5b505af1158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c91906143ad565b9094509250611fac8b8786612a48565b611fb78a8785612a48565b50506001600055909890975095505050505050565b7f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f581565b60035460009081908190612030907f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5908f906001600160a01b0316612988565b905060008761203f578c612043565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf9061207e903390309086908f908e908e908e906004016144cc565b600060405180830381600087803b15801561209857600080fd5b505af11580156120ac573d6000803e3d6000fd5b505050506120be8e8e8e8e8e8e61042a565b909f909e509c50505050505050505050505050565b600080600083428110156120f95760405162461bcd60e51b815260040161044e906146fd565b6002600054141561213f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905554604051633351733f60e01b81526001600160a01b0390911690633351733f9061217e908f908f908f908f908f908f90600401614565565b6040805180830381600087803b15801561219757600080fd5b505af11580156121ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cf91906143ad565b909450925060006122017f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58e8e612988565b905061220f8d338388612dc0565b61221b8c338387612dc0565b6040516335313c2160e11b81526001600160a01b03821690636a62784290612247908a906004016144b8565b602060405180830381600087803b15801561226157600080fd5b505af1158015612275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122999190614330565b925050600160008190555050985098509895505050505050565b600080600083428110156122d95760405162461bcd60e51b815260040161044e906146fd565b6002600054141561231f576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b6002600081905554600354604051633351733f60e01b81526001600160a01b0392831692633351733f92612363928f92909116908e9034908f908f90600401614565565b6040805180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b491906143ad565b60035491955093506000906123f5907f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5908d906001600160a01b0316612988565b90506124038b338388612dc0565b600360009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561245357600080fd5b505af1158015612467573d6000803e3d6000fd5b505060035460405163a9059cbb60e01b81526001600160a01b03909116935063a9059cbb925061249e91508490889060040161459b565b602060405180830381600087803b1580156124b857600080fd5b505af11580156124cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f09190614314565b6124f657fe5b6040516335313c2160e11b81526001600160a01b03821690636a62784290612522908a906004016144b8565b602060405180830381600087803b15801561253c57600080fd5b505af1158015612550573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125749190614330565b92508334111561258a5761258a33853403612b8f565b5060016000819055505096509650969350505050565b6003546001600160a01b03161580156125c257506002546001600160a01b0316155b6125cb57600080fd5b6001546001600160a01b031633146125f55760405162461bcd60e51b815260040161044e90614613565b600380546001600160a01b039384166001600160a01b03199182161790915560028054929093169116179055565b606081428110156126465760405162461bcd60e51b815260040161044e906146fd565b6002600054141561268c576040805162461bcd60e51b815260206004820152601f60248201526000805160206147b4833981519152604482015290519081900360640190fd5b600260009081556003546001600160a01b03169087908790816126ab57fe5b90506020020160208101906126c0919061401d565b6001600160a01b0316146126e65760405162461bcd60e51b815260040161044e906146c6565b6127447f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f588888880806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612fa392505050565b9150348260008151811061275457fe5b6020026020010151111561277a5760405162461bcd60e51b815260040161044e90614632565b60035482516001600160a01b039091169063d0e30db090849060009061279c57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156127cf57600080fd5b505af11580156127e3573d6000803e3d6000fd5b50506003546001600160a01b0316925063a9059cbb915061282b90507f00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f58989600081610f4457fe5b8460008151811061283857fe5b60200260200101516040518363ffffffff1660e01b815260040161285d92919061459b565b602060405180830381600087803b15801561287757600080fd5b505af115801561288b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128af9190614314565b6128b557fe5b600254604051631a70b66160e21b81526001600160a01b03909116906369c2d984906128e99085908a908a906004016145e3565b600060405180830381600087803b15801561290357600080fd5b505af1158015612917573d6000803e3d6000fd5b5050505061294c86866001898990500381811061293057fe5b9050602002016020810190612945919061401d565b8589612a48565b8160008151811061295957fe5b602002602001015134111561162c5761162c338360008151811061297957fe5b60200260200101513403612b8f565b600080600061299785856130d5565b604080516bffffffffffffffffffffffff19606094851b811660208084019190915293851b81166034830152825160288184030181526048830184528051908501206001600160f81b031960688401529a90941b9093166069840152607d8301989098527ffc84b622ba228c468b74c2d99bfe9454ffac280ac017f05a02feb9f739aeb1e4609d808401919091528851808403909101815260bd909201909752805196019590952095945050505050565b604051632a4d95e760e21b81526000906001600160a01b037f0000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e169063a936579c90612a979087906004016144b8565b60206040518083038186803b158015612aaf57600080fd5b505afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190614039565b90506001600160a01b038116612b0757612b028484846131b3565b612b89565b60405163f3fef3a360e01b81526001600160a01b0385169063f3fef3a390612b35908690869060040161459b565b602060405180830381600087803b158015612b4f57600080fd5b505af1158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190614330565b505b50505050565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b60208310612bdb5780518252601f199092019160209182019101612bbc565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612c3d576040519150601f19603f3d011682016040523d82523d6000602084013e612c42565b606091505b5050905080612c825760405162461bcd60e51b81526004018080602001828103825260348152602001806148056034913960400191505060405180910390fd5b505050565b6060600282511015612ce0576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a20494e56414c49445f5041544800604482015290519081900360640190fd5b815167ffffffffffffffff81118015612cf857600080fd5b50604051908082528060200260200182016040528015612d22578160200160208202803683370190505b5090508281600081518110612d3357fe5b60200260200101818152505060005b6001835103811015612db857612d96828281518110612d5d57fe5b6020026020010151848381518110612d7157fe5b6020026020010151858460010181518110612d8857fe5b6020026020010151886132ff565b828260010181518110612da557fe5b6020908102919091010152600101612d42565b509392505050565b604051632a4d95e760e21b81526000906001600160a01b037f0000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e169063a936579c90612e0f9088906004016144b8565b60206040518083038186803b158015612e2757600080fd5b505afa158015612e3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5f9190614039565b90506001600160a01b038116612e8057612e7b85858585613668565b612b87565b604051635ac402df60e11b81526000906001600160a01b0387169063b58805be90612eaf908690600401614734565b602060405180830381600087803b158015612ec957600080fd5b505af1158015612edd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f019190614330565b9050612f0f82863084613668565b612f1a8287836137c4565b6040516311f9fbc960e21b81526001600160a01b038716906347e7ef2490612f48908790859060040161459b565b602060405180830381600087803b158015612f6257600080fd5b505af1158015612f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9a9190614330565b50505050505050565b6060600282511015612ffc576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a20494e56414c49445f5041544800604482015290519081900360640190fd5b815167ffffffffffffffff8111801561301457600080fd5b5060405190808252806020026020018201604052801561303e578160200160208202803683370190505b509050828160018351038151811061305257fe5b60209081029190910101528151600019015b8015612db8576130b282828151811061307957fe5b602002602001015184600184038151811061309057fe5b60200260200101518584815181106130a457fe5b602002602001015188613910565b8260018303815181106130c157fe5b602090810291909101015260001901613064565b600080826001600160a01b0316846001600160a01b031614156131295760405162461bcd60e51b81526004018080602001828103825260268152602001806148b56026913960400191505060405180910390fd5b826001600160a01b0316846001600160a01b03161061314957828461314c565b83835b90925090506001600160a01b0382166131ac576040805162461bcd60e51b815260206004820152601f60248201527f496d706f737369626c654c6962726172793a205a45524f5f4144445245535300604482015290519081900360640190fd5b9250929050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061322f5780518252601f199092019160209182019101613210565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613291576040519150601f19603f3d011682016040523d82523d6000602084013e613296565b606091505b50915091508180156132c45750805115806132c457508080602001905160208110156132c157600080fd5b50515b612b875760405162461bcd60e51b815260040180806020018281038252602d815260200180614888602d913960400191505060405180910390fd5b600080851161333f5760405162461bcd60e51b815260040180806020018281038252602c815260200180614788602c913960400191505060405180910390fd5b6000806000806000806133528a8a6130d5565b509050806001600160a01b03168a6001600160a01b0316149150613377888b8b613c2b565b80955081975082985050505050600080600080856001600160a01b031663e94e3d8d6040518163ffffffff1660e01b815260040160606040518083038186803b1580156133c357600080fd5b505afa1580156133d7573d6000803e3d6000fd5b505050506040513d60608110156133ed57600080fd5b5080516020820151604090920151945061ffff16925090506134148e612710849003613ced565b9650600081600381111561342457fe5b14806134445750600181600381111561343957fe5b148015613444575084155b806134625750600281600381111561345857fe5b1480156134625750845b61349d5760405162461bcd60e51b81526004018080602001828103825260248152602001806148396024913960400191505060405180910390fd5b505080156135f157600080856001600160a01b031663b6b9f61b6040518163ffffffff1660e01b8152600401604080518083038186803b1580156134e057600080fd5b505afa1580156134f4573d6000803e3d6000fd5b505050506040513d604081101561350a57600080fd5b5080516020909101519092509050600061354661354184848961352d578c61352f565b8d5b8a61353a578e61353c565b8d5b613d56565b613de3565b905061355481612710613ced565b61356a6135638c612710613ced565b8a90613e35565b106135d5576135858661357d578261357f565b835b82613e84565b9450808a1080156135965750818314155b156135d0576135a58982613e9b565b9a506135c76135c06127106135ba848e613e9b565b90613ced565b8990613e9b565b97508099508098505b6135ed565b6135ea866135e3578361357f565b8282613e84565b94505b5050505b60006136076136008885613e35565b8790613ced565b905060006136258761361f6127106135ba8d89613e35565b90613e35565b9050600081838161363257fe5b04905088811161364b57613646818c613e35565b613655565b613655898c613e35565b9f9e505050505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b602083106136ec5780518252601f1990920191602091820191016136cd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461374e576040519150601f19603f3d011682016040523d82523d6000602084013e613753565b606091505b5091509150818015613781575080511580613781575080806020019051602081101561377e57600080fd5b50515b6137bc5760405162461bcd60e51b81526004018080602001828103825260318152602001806147d46031913960400191505060405180910390fd5b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1781529251825160009485949389169392918291908083835b602083106138405780518252601f199092019160209182019101613821565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146138a2576040519150601f19603f3d011682016040523d82523d6000602084013e6138a7565b606091505b50915091508180156138d55750805115806138d557508080602001905160208110156138d257600080fd5b50515b612b875760405162461bcd60e51b815260040180806020018281038252602b81526020018061485d602b913960400191505060405180910390fd5b60008085116139505760405162461bcd60e51b815260040180806020018281038252602c815260200180614788602c913960400191505060405180910390fd5b60008060008060008060008060006139688d8d6130d5565b506001600160a01b038e81169116149450600090506139888b8e8e613c2b565b809350819a50829b505050506000816001600160a01b031663e94e3d8d6040518163ffffffff1660e01b815260040160606040518083038186803b1580156139cf57600080fd5b505afa1580156139e3573d6000803e3d6000fd5b505050506040513d60608110156139f957600080fd5b508051602082015160409092015161ffff9091169850955090506000816003811115613a2157fe5b1480613a4157506001816003811115613a3657fe5b148015613a41575085155b80613a5f57506002816003811115613a5557fe5b148015613a5f5750855b613a9a5760405162461bcd60e51b81526004018080602001828103825260248152602001806148396024913960400191505060405180910390fd5b816001600160a01b031663b6b9f61b6040518163ffffffff1660e01b8152600401604080518083038186803b158015613ad257600080fd5b505afa158015613ae6573d6000803e3d6000fd5b505050506040513d6040811015613afc57600080fd5b50805160209091015190945092505083159050613bc0576000613b3b613541848488613b28578b613b2a565b8c5b89613b35578d61353c565b8c613d56565b905080613b518f8a613e9b90919063ffffffff16565b10613b6b57613b64856135e3578361357f565b9650613bbe565b613b798561357d578261357f565b96508088118015613b8a5750818314155b15613bbe57613b9f6127106135ba838c613e9b565b9950613bb5613bae8983613e9b565b8f90613e9b565b9d508097508098505b505b5060009150613bd990506127106135ba8d818a89613e35565b90506000613bf18c613beb8888613e35565b90613e9b565b9050613c1b600161361f8661271003613c15858781613c0c57fe5b8e919004613e35565b90613eeb565b9c9b505050505050505050505050565b600080600080613c3b86866130d5565b509050613c49878787612988565b9150600080836001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401604080518083038186803b158015613c8657600080fd5b505afa158015613c9a573d6000803e3d6000fd5b505050506040513d6040811015613cb057600080fd5b50805160209091015190925090506001600160a01b0388811690841614613cd8578082613cdb565b81815b909a9099509397509295505050505050565b6000811580613d0857505080820282828281613d0557fe5b04145b613d50576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015290519081900360640190fd5b92915050565b600080828411613d7057613d6b856001613e9b565b613d7b565b613d7b866001613e9b565b90506000613d8f600161361f846002613ced565b90506000613db5613da1836002613ced565b613c15613dae8989613e35565b8690613ced565b9050600281613dd5613dcb85613c158b8b613ced565b6002850a01613de3565b010a98975050505050505050565b60006003821115613e26575080600160028204015b81811015613e2057809150600281828581613e0f57fe5b040181613e1857fe5b049050613df8565b50613e30565b8115613e30575060015b919050565b80820182811015613d50576040805162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015290519081900360640190fd5b6000613e94600019840183613ced565b9392505050565b80820382811115613d50576040805162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015290519081900360640190fd5b6000613e9483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060008183613fb45760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613f79578181015183820152602001613f61565b50505050905090810190601f168015613fa65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581613fc057fe5b0495945050505050565b60008083601f840112613fdb578182fd5b50813567ffffffffffffffff811115613ff2578182fd5b60208301915083602080830285010111156131ac57600080fd5b803560ff81168114613e3057600080fd5b60006020828403121561402e578081fd5b8135613e9481614761565b60006020828403121561404a578081fd5b8151613e9481614761565b60008060408385031215614067578081fd5b823561407281614761565b9150602083013561408281614761565b809150509250929050565b600080600080600080600060e0888a0312156140a7578283fd5b87356140b281614761565b965060208801356140c281614761565b955060408801359450606088013593506080880135925060a08801356140e781614761565b8092505060c0880135905092959891949750929550565b60008060008060008060008060008060006101608c8e03121561411f578384fd5b8b3561412a81614761565b9a5060208c013561413a81614761565b995060408c0135985060608c0135975060808c0135965060a08c013561415f81614761565b955060c08c0135945060e08c013561417681614779565b93506141856101008d0161400c565b92506101208c013591506101408c013590509295989b509295989b9093969950565b600080600080600080600080610100898b0312156141c3578384fd5b88356141ce81614761565b975060208901356141de81614761565b965060408901359550606089013594506080890135935060a0890135925060c089013561420a81614761565b8092505060e089013590509295985092959890939650565b60008060008060008060c0878903121561423a578182fd5b863561424581614761565b9550602087013594506040870135935060608701359250608087013561426a81614761565b8092505060a087013590509295509295509295565b6000806000806000806000806000806101408b8d03121561429e578384fd5b8a356142a981614761565b995060208b0135985060408b0135975060608b0135965060808b01356142ce81614761565b955060a08b0135945060c08b01356142e581614779565b93506142f360e08c0161400c565b92506101008b013591506101208b013590509295989b9194979a5092959850565b600060208284031215614325578081fd5b8151613e9481614779565b600060208284031215614341578081fd5b5051919050565b60008060008060006080868803121561435f578283fd5b85359450602086013567ffffffffffffffff81111561437c578384fd5b61438888828901613fca565b909550935050604086013561439c81614761565b949793965091946060013592915050565b600080604083850312156143bf578182fd5b505080516020909101519092909150565b60008060008060008060a087890312156143e8578384fd5b8635955060208701359450604087013567ffffffffffffffff81111561440c578485fd5b61441889828a01613fca565b909550935050606087013561442c81614761565b80925050608087013590509295509295509295565b60008284526020808501945082825b8581101561447e57813561446381614761565b6001600160a01b031687529582019590820190600101614450565b509495945050505050565b6000815180845260208085019450808401835b8381101561447e5781518752958201959082019060010161449c565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b6001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b6001600160a01b03929092168252602082015260400190565b6000602082526145c8602083018486614441565b949350505050565b600060208252613e946020830184614489565b6000604082526145f66040830186614489565b8281036020840152614609818587614441565b9695505050505050565b60208082526005908201526449463a203f60d81b604082015260600190565b60208082526028908201527f496d706f737369626c65526f757465723a204558434553534956455f494e50556040820152671517d05353d5539560c21b606082015260800190565b6020808252602c908201527f496d706f737369626c65526f757465723a20494e53554646494349454e545f4f60408201526b155514155517d05353d5539560a21b606082015260800190565b6020808252601e908201527f496d706f737369626c65526f757465723a20494e56414c49445f504154480000604082015260600190565b60208082526019908201527f496d706f737369626c65526f757465723a204558504952454400000000000000604082015260600190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6001600160a01b038116811461477657600080fd5b50565b801515811461477657600080fdfe496d706f737369626c654c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e545265656e7472616e637947756172643a207265656e7472616e742063616c6c005472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472616e7366657246726f6d206661696c65645472616e7366657248656c7065723a3a736166655472616e736665724554483a20455448207472616e73666572206661696c6564496d706f737369626c654c6962726172793a2054524144455f4e4f545f414c4c4f5745445472616e7366657248656c7065723a3a73616665417070726f76653a20617070726f7665206661696c65645472616e7366657248656c7065723a3a736166655472616e736665723a207472616e73666572206661696c6564496d706f737369626c654c6962726172793a204944454e544943414c5f414444524553534553a26469706673582212201d47bb6aa4c4e5a635ca01716e6be81c6af6f3e867a84fc2495526c9765ca44264736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f50000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e000000000000000000000000554a45ea949851f4b4047ab958a985b4d4884ddd
-----Decoded View---------------
Arg [0] : _pairFactory (address): 0x56E59989BCaf633ee60aBc4437F82A91A765f4f5
Arg [1] : _wrapFactory (address): 0x7f6f6dF046950982E2a22f43CE4C1F443F42383e
Arg [2] : _utilitySettingAdmin (address): 0x554A45EA949851f4b4047Ab958a985B4d4884ddd
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000056e59989bcaf633ee60abc4437f82a91a765f4f5
Arg [1] : 0000000000000000000000007f6f6df046950982e2a22f43ce4c1f443f42383e
Arg [2] : 000000000000000000000000554a45ea949851f4b4047ab958a985b4d4884ddd
Deployed Bytecode Sourcemap
1006:29047:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2113:4;;-1:-1:-1;;;;;2113:4:2;2099:10;:18;2092:26;;;;1006:29047;;;;;1156:45;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;22789:836;;;;;;;;;;-1:-1:-1;22789:836:2;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;10660:856::-;;;;;;;;;;-1:-1:-1;10660:856:2;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;24525:699::-;;;;;;;;;;-1:-1:-1;24525:699:2;;;;;:::i;:::-;;:::i;5182:729::-;;;;;;;;;;-1:-1:-1;5182:729:2;;;;;:::i;:::-;;:::i;9212:834::-;;;;;;;;;;-1:-1:-1;9212:834:2;;;;;:::i;:::-;;:::i;1250:39::-;;;;;;;;;;;;;:::i;29241:810::-;;;;;;;;;;-1:-1:-1;29241:810:2;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;13461:707::-;;;;;;;;;;-1:-1:-1;13461:707:2;;;;;:::i;:::-;;:::i;15897:805::-;;;;;;;;;;-1:-1:-1;15897:805:2;;;;;:::i;:::-;;:::i;7773:818::-;;;;;;:::i;:::-;;:::i;6529:689::-;;;;;;;;;;-1:-1:-1;6529:689:2;;;;;:::i;:::-;;:::i;1344:28::-;;;;;;;;;;;;;:::i;27512:860::-;;;;;;;;;;-1:-1:-1;27512:860:2;;;;;:::i;:::-;;:::i;14600:831::-;;;;;;:::i;:::-;;:::i;21286:790::-;;;;;;;;;;-1:-1:-1;21286:790:2;;;;;:::i;:::-;;:::i;1109:41::-;;;;;;;;;;;;;:::i;26066:706::-;;;;;;;;;;-1:-1:-1;26066:706:2;;;;;:::i;:::-;;:::i;17596:955::-;;;;;;;;;;-1:-1:-1;17596:955:2;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;19436:1113::-;;;;;;:::i;:::-;;:::i;2535:278::-;;;;;;;;;;-1:-1:-1;2535:278:2;;;;;:::i;:::-;;:::i;12082:911::-;;;;;;:::i;:::-;;:::i;1156:45::-;;;:::o;22789:836::-;23044:19;23065:17;23012:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;;;;;;;;;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;23151:4:2::2;::::0;23109:47:::2;::::0;23135:7:::2;::::0;23144:5;;-1:-1:-1;;;;;23151:4:2::2;23109:25;:47::i;:::-;23166:63;::::0;-1:-1:-1;;;23166:63:2;;23094:62;;-1:-1:-1;;;;;;23166:34:2;::::2;::::0;::::2;::::0;:63:::2;::::0;23201:10:::2;::::0;23094:62;;23219:9;;23166:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;23319:15:2::2;::::0;23384:4:::2;::::0;23292:178:::2;::::0;-1:-1:-1;;;23292:178:2;;-1:-1:-1;;;;;23319:15:2;;::::2;::::0;23292:59:::2;::::0;:178:::2;::::0;23365:5;;23384:4;;::::2;::::0;23402;;23420:14;;23448:12;;23292:178:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23265:205:::0;;-1:-1:-1;23265:205:2;-1:-1:-1;23480:42:2::2;23499:5:::0;23506:2;23265:205;23480:18:::2;:42::i;:::-;23538:4;::::0;23532:31:::2;::::0;-1:-1:-1;;;23532:31:2;;-1:-1:-1;;;;;23538:4:2;;::::2;::::0;23532:20:::2;::::0;:31:::2;::::0;23553:9;;23532:31:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;23573:45;23604:2;23608:9;23573:30;:45::i;:::-;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;22789:836:2;;;;-1:-1:-1;22789:836:2;-1:-1:-1;;;;;22789:836:2:o;10660:856::-;10897:24;10865:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;10966:4:2::2;::::0;-1:-1:-1;;;;;10966:4:2::2;10941::::0;;-1:-1:-1;;10946:15:2;;10941:21;;::::2;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;10941:29:2::2;;10933:72;;;;-1:-1:-1::0;;;10933:72:2::2;;;;;;;:::i;:::-;11025:56;11057:7;11066:8;11076:4;;11025:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;11025:31:2::2;::::0;-1:-1:-1;;;11025:56:2:i:2;:::-;11015:66;;11130:12;11099:7;11124:1;11107:7;:14;:18;11099:27;;;;;;;;;;;;;;:43;;11091:100;;;;-1:-1:-1::0;;;11091:100:2::2;;;;;;;:::i;:::-;11201:103;11218:4;;11223:1;11218:7;;;;;;;;;;;;;;;;;;;;:::i;:::-;11227:10;11239:52;11265:7;11274:4;;11279:1;11274:7;;;;;;;;;;;;;;;;;;;;:::i;:::-;11283:4;;11288:1;11283:7;;;;;;;;;;;;;;;;;;;;:::i;:::-;11239:25;:52::i;:::-;11293:7;11301:1;11293:10;;;;;;;;;;;;;;11201:16;:103::i;:::-;11341:15;::::0;11314:63:::2;::::0;-1:-1:-1;;;11314:63:2;;-1:-1:-1;;;;;11341:15:2;;::::2;::::0;11314:48:::2;::::0;:63:::2;::::0;11363:7;;11372:4;;;;11314:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;11393:4:2::2;::::0;11416:14;;-1:-1:-1;;;;;11393:4:2;;::::2;::::0;-1:-1:-1;11387:20:2::2;::::0;-1:-1:-1;11408:7:2;;-1:-1:-1;;11416:18:2;;;11408:27;::::2;;;;;;;;;;;11387:49;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;11446:63;11477:2;11481:7;11506:1;11489:7;:14;:18;11481:27;;;;;;;;;;;;;;11446:30;:63::i;:::-;-1:-1:-1::0;1645:1:19::1;2570:7;:22:::0;10660:856:2;;-1:-1:-1;;;;;;10660:856:2:o;24525:699::-;24858:15;24875;24902:12;24917:50;24943:7;24952:6;24960;24917:25;:50::i;:::-;24902:65;;24977:13;24993:10;:36;;25020:9;24993:36;;;-1:-1:-1;;24993:36:2;25039:81;;-1:-1:-1;;;25039:81:2;;24977:52;;-1:-1:-1;;;;;;25039:28:2;;;;;:81;;25068:10;;25088:4;;24977:52;;25102:8;;25112:1;;25115;;25118;;25039:81;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25137:80;25153:6;25161;25169:9;25180:10;25192;25204:2;25208:8;25137:15;:80::i;:::-;25130:87;;;;;;24525:699;;;;;;;;;;;;;;:::o;5182:729::-;5422:24;5390:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18;;;;5468:56:2::2;5500:7;5509:8;5519:4;;5468:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;5468:31:2::2;::::0;-1:-1:-1;;;5468:56:2:i:2;:::-;5458:66;;5573:12;5542:7;5567:1;5550:7;:14;:18;5542:27;;;;;;;;;;;;;;:43;;5534:100;;;;-1:-1:-1::0;;;5534:100:2::2;;;;;;;:::i;:::-;5644:103;5661:4;;5666:1;5661:7;;;;;;5644:103;5784:15;::::0;5757:63:::2;::::0;-1:-1:-1;;;5757:63:2;;-1:-1:-1;;;;;5784:15:2;;::::2;::::0;5757:48:::2;::::0;:63:::2;::::0;5806:7;;5815:4;;;;5757:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;5830:74;5849:4;;5868:1;5854:4;;:11;;:15;5849:21;;;;;;;;;;;;;;;;;;;;:::i;:::-;5872:2;5876:7;5901:1;5884:7;:14;:18;5876:27;;;;;;;;;;;;;;5830:18;:74::i;9212:834::-:0;9449:24;9417:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;9518:4:2::2;::::0;-1:-1:-1;;;;;9518:4:2::2;9493::::0;;-1:-1:-1;;9498:15:2;;9493:21;;::::2;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;9493:29:2::2;;9485:72;;;;-1:-1:-1::0;;;9485:72:2::2;;;;;;;:::i;:::-;9577:56;9608:7;9617:9;9628:4;;9577:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;9577:30:2::2;::::0;-1:-1:-1;;;9577:56:2:i:2;:::-;9567:66;;9665:11;9651:7;9659:1;9651:10;;;;;;;;;;;;;;:25;;9643:78;;;;-1:-1:-1::0;;;9643:78:2::2;;;;;;;:::i;1250:39::-:0;;;-1:-1:-1;;;;;1250:39:2;;:::o;29241:810::-;29673:4;;29587:17;;;;29631:47;;29657:7;;29666:5;;-1:-1:-1;;;;;29673:4:2;29631:25;:47::i;:::-;29616:62;;29688:13;29704:10;:36;;29731:9;29704:36;;;-1:-1:-1;;29704:36:2;29750:81;;-1:-1:-1;;;29750:81:2;;29688:52;;-1:-1:-1;;;;;;29750:28:2;;;;;:81;;29779:10;;29799:4;;29688:52;;29813:8;;29823:1;;29826;;29829;;29750:81;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29853:191;29914:5;29933:9;29956:14;29984:12;30010:2;30026:8;29853:47;:191::i;:::-;29841:203;29241:810;-1:-1:-1;;;;;;;;;;;;;29241:810:2:o;13461:707::-;13698:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18;;;;13731:101:2::2;13748:4;;13753:1;13748:7;;;;;;;;;;;;;;;;;;;;:::i;:::-;13757:10;13769:52;13795:7;13804:4;;13809:1;13804:7;;;;;;;;;;;;;;;;;;;;:::i;:::-;13813:4;;13818:1;13813:7;;;;;;13769:52;13823:8;13731:16;:101::i;:::-;13869:15;::::0;13842:83:::2;::::0;-1:-1:-1;;;13842:83:2;;-1:-1:-1;;;;;13869:15:2;;::::2;::::0;13842:77:::2;::::0;:83:::2;::::0;13920:4;;;;13842:83:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;13935:15;13960:4;;13979:1;13965:4;;:11;;:15;13960:21;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;13953:39:2::2;;14001:4;13953:54;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13935:72;;14036:12;14025:7;:23;;14017:80;;;;-1:-1:-1::0;;;14017:80:2::2;;;;;;;:::i;:::-;14107:54;14126:4:::0;;-1:-1:-1;;14131:15:2;;14126:21;;::::2;;;;;;;;;;;;;;;;;;:::i;:::-;14149:2;14153:7;14107:18;:54::i;:::-;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;-1:-1:-1;;;;;;13461:707:2:o;15897:805::-;16131:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;16197:4:2::2;::::0;-1:-1:-1;;;;;16197:4:2::2;16172::::0;;-1:-1:-1;;16177:15:2;;16172:21;;::::2;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;16172:29:2::2;;16164:72;;;;-1:-1:-1::0;;;16164:72:2::2;;;;;;;:::i;:::-;16246:101;16263:4;;16268:1;16263:7;;;;;;16246:101;16384:15;::::0;16357:83:::2;::::0;-1:-1:-1;;;16357:83:2;;-1:-1:-1;;;;;16384:15:2;;::::2;::::0;16357:77:::2;::::0;:83:::2;::::0;16435:4;;;;16357:83:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;16477:4:2::2;::::0;16470:37:::2;::::0;-1:-1:-1;;;16470:37:2;;16450:17:::2;::::0;-1:-1:-1;;;;;;16477:4:2;;::::2;::::0;-1:-1:-1;16470:22:2::2;::::0;:37:::2;::::0;16501:4:::2;::::0;16470:37:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16450:57;;16538:12;16525:9;:25;;16517:82;;;;-1:-1:-1::0;;;16517:82:2::2;;;;;;;:::i;:::-;16615:4;::::0;16609:31:::2;::::0;-1:-1:-1;;;16609:31:2;;-1:-1:-1;;;;;16615:4:2;;::::2;::::0;16609:20:::2;::::0;:31:::2;::::0;16630:9;;16609:31:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;16650:45;16681:2;16685:9;16650:30;:45::i;7773:818::-:0;7992:24;7960:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;8047:4:2::2;::::0;-1:-1:-1;;;;;8047:4:2::2;::::0;8036;;;;:7;::::2;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;8036:15:2::2;;8028:58;;;;-1:-1:-1::0;;;8028:58:2::2;;;;;;;:::i;:::-;8106:57;8138:7;8147:9;8158:4;;8106:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;8106:31:2::2;::::0;-1:-1:-1;;;8106:57:2:i:2;:::-;8096:67;;8212:12;8181:7;8206:1;8189:7;:14;:18;8181:27;;;;;;;;;;;;;;:43;;8173:100;;;;-1:-1:-1::0;;;8173:100:2::2;;;;;;;:::i;:::-;8289:4;::::0;8310:10;;-1:-1:-1;;;;;8289:4:2;;::::2;::::0;8283:19:::2;::::0;8310:7;;8289:4:::2;::::0;8310:10:::2;;;;;;;;;;8283:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;8346:4:2::2;::::0;-1:-1:-1;;;;;8346:4:2::2;::::0;-1:-1:-1;8340:20:2::2;::::0;-1:-1:-1;8361:52:2::2;::::0;-1:-1:-1;8387:7:2::2;8396:4:::0;;8346::::2;8396:7:::0;::::2;;;8361:52;8415:7;8423:1;8415:10;;;;;;;;;;;;;;8340:86;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8333:94;;;;8464:15;::::0;8437:63:::2;::::0;-1:-1:-1;;;8437:63:2;;-1:-1:-1;;;;;8464:15:2;;::::2;::::0;8437:48:::2;::::0;:63:::2;::::0;8486:7;;8495:4;;;;8437:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;8510:74;8529:4;;8548:1;8534:4;;:11;;:15;8529:21;;;;;;8510:74;-1:-1:-1::0;1645:1:19::1;2570:7;:22:::0;7773:818:2;;-1:-1:-1;;;;;7773:818:2:o;6529:689::-;6769:24;6737:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18;;;;6815:56:2::2;6846:7;6855:9;6866:4;;6815:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;6815:30:2::2;::::0;-1:-1:-1;;;6815:56:2:i:2;:::-;6805:66;;6903:11;6889:7;6897:1;6889:10;;;;;;;;;;;;;;:25;;6881:78;;;;-1:-1:-1::0;;;6881:78:2::2;;;;;;;:::i;:::-;6969:103;6986:4;;6991:1;6986:7;;;;;;6969:103;7109:15;::::0;7082:63:::2;::::0;-1:-1:-1;;;7082:63:2;;-1:-1:-1;;;;;7109:15:2;;::::2;::::0;7082:48:::2;::::0;:63:::2;::::0;7131:7;;7140:4;;;;7082:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;7155:56;7174:4;;7193:1;7179:4;;:11;;:15;7174:21;;;;;;;;;;;;;;;;;;;;:::i;:::-;7197:2;7201:9;7155:18;:56::i;1344:28::-:0;;;-1:-1:-1;;;;;1344:28:2;;:::o;27512:860::-;27796:17;27764:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;27882:4:2::2;::::0;27840:47:::2;::::0;27866:7:::2;::::0;27875:5;;-1:-1:-1;;;;;27882:4:2::2;27840:25;:47::i;:::-;27897:63;::::0;-1:-1:-1;;;27897:63:2;;27825:62;;-1:-1:-1;;;;;;27897:34:2;::::2;::::0;::::2;::::0;:63:::2;::::0;27932:10:::2;::::0;27825:62;;27950:9;;27897:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;28039:15:2::2;::::0;28104:4:::2;::::0;28012:178:::2;::::0;-1:-1:-1;;;28012:178:2;;-1:-1:-1;;;;;28039:15:2;;::::2;::::0;28012:59:::2;::::0;:178:::2;::::0;28085:5;;28104:4;;::::2;::::0;28122;;28140:14;;28168:12;;28012:178:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;28230:38;::::0;-1:-1:-1;;;28230:38:2;;27996:194;;-1:-1:-1;28200:69:2::2;::::0;-1:-1:-1;28219:5:2;;28226:2;;-1:-1:-1;;;;;28230:23:2;::::2;::::0;::::2;::::0;:38:::2;::::0;28262:4:::2;::::0;28230:38:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;28200:18;:69::i;:::-;28285:4;::::0;28279:31:::2;::::0;-1:-1:-1;;;28279:31:2;;-1:-1:-1;;;;;28285:4:2;;::::2;::::0;28279:20:::2;::::0;:31:::2;::::0;28300:9;;28279:31:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;28320:45;28351:2;28355:9;28320:30;:45::i;:::-;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;27512:860:2;;-1:-1:-1;;;;;;27512:860:2:o;14600:831::-;14816:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;14868:4:2::2;::::0;-1:-1:-1;;;;;14868:4:2::2;::::0;14857;;;;:7;::::2;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;14857:15:2::2;;14849:58;;;;-1:-1:-1::0;;;14849:58:2::2;;;;;;;:::i;:::-;14961:4;::::0;14955:38:::2;::::0;;-1:-1:-1;;;14955:38:2;;;;14936:9:::2;::::0;-1:-1:-1;;;;;14961:4:2::2;::::0;14955:19:::2;::::0;14936:9;;14955:38:::2;::::0;;::::2;::::0;14917:16:::2;::::0;14955:38;;;;;;;;14936:9;14961:4;14955:38;::::2;;::::0;::::2;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;15016:4:2::2;::::0;-1:-1:-1;;;;;15016:4:2::2;::::0;-1:-1:-1;15010:20:2::2;::::0;-1:-1:-1;15031:52:2::2;::::0;-1:-1:-1;15057:7:2::2;15066:4:::0;;15016::::2;15066:7:::0;::::2;;;15031:52;15085:8;15010:84;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15003:92;;;;15132:15;::::0;15105:83:::2;::::0;-1:-1:-1;;;15105:83:2;;-1:-1:-1;;;;;15132:15:2;;::::2;::::0;15105:77:::2;::::0;:83:::2;::::0;15183:4;;;;15105:83:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;15198:15;15223:4;;15242:1;15228:4;;:11;;:15;15223:21;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;15216:39:2::2;;15264:4;15216:54;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15198:72;;15299:12;15288:7;:23;;15280:80;;;;-1:-1:-1::0;;;15280:80:2::2;;;;;;;:::i;:::-;15370:54;15389:4:::0;;-1:-1:-1;;15394:15:2;;15389:21;;::::2;;;;;;;;;;;;;;;;;;:::i;:::-;15412:2;15416:7;15370:18;:54::i;21286:790::-:0;21557:15;21574;21525:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;21616:50:2::2;21642:7;21651:6:::0;21659;21616:25:::2;:50::i;:::-;21676:63;::::0;-1:-1:-1;;;21676:63:2;;21601:65;;-1:-1:-1;;;;;;21676:34:2;::::2;::::0;::::2;::::0;:63:::2;::::0;21711:10:::2;::::0;21601:65;;21729:9;;21676:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;21823:15:2::2;::::0;21796:175:::2;::::0;-1:-1:-1;;;21796:175:2;;-1:-1:-1;;;;;21823:15:2;;::::2;::::0;21796:59:::2;::::0;:175:::2;::::0;21869:6;;21889;;21909:4;;21927:10;;21951;;21796:175:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;21775:196:::0;;-1:-1:-1;21775:196:2;-1:-1:-1;21981:39:2::2;22000:6:::0;22008:2;21775:196;21981:18:::2;:39::i;:::-;22030;22049:6;22057:2;22061:7;22030:18;:39::i;:::-;-1:-1:-1::0;;1645:1:19::1;2570:7;:22:::0;21286:790:2;;;;-1:-1:-1;21286:790:2;-1:-1:-1;;;;;;21286:790:2:o;1109:41::-;;;:::o;26066:706::-;26490:4;;26383:19;;;;;;26448:47;;26474:7;;26483:5;;-1:-1:-1;;;;;26490:4:2;26448:25;:47::i;:::-;26433:62;;26505:13;26521:10;:36;;26548:9;26521:36;;;-1:-1:-1;;26521:36:2;26567:81;;-1:-1:-1;;;26567:81:2;;26505:52;;-1:-1:-1;;;;;;26567:28:2;;;;;:81;;26596:10;;26616:4;;26505:52;;26630:8;;26640:1;;26643;;26646;;26567:81;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26685:80;26704:5;26711:9;26722:14;26738:12;26752:2;26756:8;26685:18;:80::i;:::-;26658:107;;;;-1:-1:-1;26066:706:2;-1:-1:-1;;;;;;;;;;;;;26066:706:2:o;17596:955::-;17964:15;17993;18022:17;17903:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;18112:15:2;18085:210:::2;::::0;-1:-1:-1;;;18085:210:2;;-1:-1:-1;;;;;18112:15:2;;::::2;::::0;18085:56:::2;::::0;:210:::2;::::0;18155:6;;18175;;18195:14;;18223;;18251:10;;18275;;18085:210:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18064:231:::0;;-1:-1:-1;18064:231:2;-1:-1:-1;18305:12:2::2;18320:50;18346:7;18355:6:::0;18363;18320:25:::2;:50::i;:::-;18305:65;;18380:51;18397:6;18405:10;18417:4;18423:7;18380:16;:51::i;:::-;18441;18458:6;18466:10;18478:4;18484:7;18441:16;:51::i;:::-;18514:30;::::0;-1:-1:-1;;;18514:30:2;;-1:-1:-1;;;;;18514:26:2;::::2;::::0;::::2;::::0;:30:::2;::::0;18541:2;;18514:30:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18502:42;;2426:1:19;1645::::1;2570:7;:22;;;;17596:955:2::0;;;;;;;;;;;;;:::o;19436:1113::-;19776:19;19809:17;19840;19715:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;19936:15:2;19998:4:::2;::::0;19909:212:::2;::::0;-1:-1:-1;;;19909:212:2;;-1:-1:-1;;;;;19936:15:2;;::::2;::::0;19909:56:::2;::::0;:212:::2;::::0;19979:5;;19998:4;;::::2;::::0;20016:18;;20048:9:::2;::::0;20071:14;;20099:12;;19909:212:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20188:4;::::0;19882:239;;-1:-1:-1;19882:239:2;-1:-1:-1;20131:12:2::2;::::0;20146:47:::2;::::0;20172:7:::2;::::0;20181:5;;-1:-1:-1;;;;;20188:4:2::2;20146:25;:47::i;:::-;20131:62;;20203:54;20220:5;20227:10;20239:4;20245:11;20203:16;:54::i;:::-;20273:4;;;;;;;;;-1:-1:-1::0;;;;;20273:4:2::2;-1:-1:-1::0;;;;;20267:19:2::2;;20294:9;20267:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;20329:4:2::2;::::0;20323:37:::2;::::0;-1:-1:-1;;;20323:37:2;;-1:-1:-1;;;;;20329:4:2;;::::2;::::0;-1:-1:-1;20323:20:2::2;::::0;-1:-1:-1;20323:37:2::2;::::0;-1:-1:-1;20344:4:2;;20350:9;;20323:37:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20316:45;;;;20383:30;::::0;-1:-1:-1;;;20383:30:2;;-1:-1:-1;;;;;20383:26:2;::::2;::::0;::::2;::::0;:30:::2;::::0;20410:2;;20383:30:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20371:42;;20439:9;20427;:21;20423:92;;;20450:65;20481:10;20505:9;20493;:21;20450:30;:65::i;:::-;2426:1:19;1645::::1;2570:7;:22;;;;19436:1113:2::0;;;;;;;;;;;:::o;2535:278::-;2623:4;;-1:-1:-1;;;;;2623:4:2;:20;:55;;;;-1:-1:-1;2647:15:2;;-1:-1:-1;;;;;2647:15:2;:31;2623:55;2615:64;;;;;;2711:19;;-1:-1:-1;;;;;2711:19:2;2697:10;:33;2689:51;;;;-1:-1:-1;;;2689:51:2;;;;;;;:::i;:::-;2750:4;:12;;-1:-1:-1;;;;;2750:12:2;;;-1:-1:-1;;;;;;2750:12:2;;;;;;;2772:15;:34;;;;;;;;;;;2535:278::o;12082:911::-;12298:24;12266:8;1492:15;1480:8;:27;;1472:65;;;;-1:-1:-1;;;1472:65:2;;;;;;;:::i;:::-;1688:1:19::1;2267:7;;:19;;2259:63;;;::::0;;-1:-1:-1;;;2259:63:19;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;;;;;;;;;2259:63:19;;;;;;;;;;;;;::::1;;1688:1;2397:7;:18:::0;;;12353:4:2::2;::::0;-1:-1:-1;;;;;12353:4:2::2;::::0;12342;;;;:7;::::2;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;12342:15:2::2;;12334:58;;;;-1:-1:-1::0;;;12334:58:2::2;;;;;;;:::i;:::-;12412:56;12443:7;12452:9;12463:4;;12412:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;12412:30:2::2;::::0;-1:-1:-1;;;12412:56:2:i:2;:::-;12402:66;;12500:9;12486:7;12494:1;12486:10;;;;;;;;;;;;;;:23;;12478:76;;;;-1:-1:-1::0;;;12478:76:2::2;;;;;;;:::i;:::-;12570:4;::::0;12591:10;;-1:-1:-1;;;;;12570:4:2;;::::2;::::0;12564:19:::2;::::0;12591:7;;12570:4:::2;::::0;12591:10:::2;;;;;;;;;;12564:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;12627:4:2::2;::::0;-1:-1:-1;;;;;12627:4:2::2;::::0;-1:-1:-1;12621:20:2::2;::::0;-1:-1:-1;12642:52:2::2;::::0;-1:-1:-1;12668:7:2::2;12677:4:::0;;12627::::2;12677:7:::0;::::2;;;12642:52;12696:7;12704:1;12696:10;;;;;;;;;;;;;;12621:86;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12614:94;;;;12745:15;::::0;12718:63:::2;::::0;-1:-1:-1;;;12718:63:2;;-1:-1:-1;;;;;12745:15:2;;::::2;::::0;12718:48:::2;::::0;:63:::2;::::0;12767:7;;12776:4;;;;12718:63:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;12791:56;12810:4;;12829:1;12815:4;;:11;;:15;12810:21;;;;;;;;;;;;;;;;;;;;:::i;:::-;12833:2;12837:9;12791:18;:56::i;:::-;12908:7;12916:1;12908:10;;;;;;;;;;;;;;12896:9;:22;12892:94;;;12920:66;12951:10;12975:7;12983:1;12975:10;;;;;;;;;;;;;;12963:9;:22;12920:30;:66::i;1251:653:17:-:0;1370:12;1395:14;1411;1429:26;1440:6;1448;1429:10;:26::i;:::-;1667:32;;;-1:-1:-1;;1667:32:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1657:43;;;;;;-1:-1:-1;;;;;;1549:306:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1518:355;;;;;;;;;1251:653;-1:-1:-1;;;;;1251:653:17:o;4186:403:2:-;4325:67;;-1:-1:-1;;;4325:67:2;;4304:18;;-1:-1:-1;;;;;4351:11:2;4325:60;;;;:67;;4386:5;;4325:67;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4304:88;-1:-1:-1;;;;;;4406:26:2;;4402:181;;4448:44;4476:5;4483:3;4488;4448:27;:44::i;:::-;4402:181;;;4523:49;;-1:-1:-1;;;4523:49:2;;-1:-1:-1;;;;;4523:39:2;;;;;:49;;4563:3;;4568;;4523:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;4402:181;4186:403;;;;:::o;1588:214:21:-;1700:12;;;1660;1700;;;;;;;;;-1:-1:-1;;;;;1678:7:21;;;1693:5;;1678:35;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1678:35:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1659:54;;;1731:7;1723:72;;;;-1:-1:-1;;;1723:72:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1588:214;;;:::o;17819:462:17:-;17953:24;18012:1;17997:4;:11;:16;;17989:60;;;;;-1:-1:-1;;;17989:60:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;18083:4;:11;18069:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18069:26:17;;18059:36;;18118:8;18105:7;18113:1;18105:10;;;;;;;;;;;;;:21;;;;;18141:9;18136:139;18170:1;18156:4;:11;:15;18152:1;:19;18136:139;;;18209:55;18222:7;18230:1;18222:10;;;;;;;;;;;;;;18234:4;18239:1;18234:7;;;;;;;;;;;;;;18243:4;18248:1;18252;18248:5;18243:11;;;;;;;;;;;;;;18256:7;18209:12;:55::i;:::-;18192:7;18200:1;18204;18200:5;18192:14;;;;;;;;;;;;;;;;;:72;18173:3;;18136:139;;;;17819:462;;;;;:::o;3175:698:2:-;3333:67;;-1:-1:-1;;;3333:67:2;;3312:18;;-1:-1:-1;;;;;3359:11:2;3333:60;;;;:67;;3394:5;;3333:67;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3312:88;-1:-1:-1;;;;;;3414:26:2;;3410:457;;3456:53;3488:5;3495:3;3500;3505;3456:31;:53::i;:::-;3410:457;;;3564:54;;-1:-1:-1;;;3564:54:2;;3540:21;;-1:-1:-1;;;;;3564:49:2;;;;;:54;;3614:3;;3564:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3540:78;;3632;3664:10;3676:3;3689:4;3696:13;3632:31;:78::i;:::-;3724:60;3751:10;3763:5;3770:13;3724:26;:60::i;:::-;3798:58;;-1:-1:-1;;;3798:58:2;;-1:-1:-1;;;;;3798:38:2;;;;;:58;;3837:3;;3842:13;;3798:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;3410:457;3175:698;;;;;:::o;18894:483:17:-;19028:24;19087:1;19072:4;:11;:16;;19064:60;;;;;-1:-1:-1;;;19064:60:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;19158:4;:11;19144:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;19144:26:17;;19134:36;;19210:9;19180:7;19205:1;19188:7;:14;:18;19180:27;;;;;;;;;;;;;;;;;:39;19246:11;;-1:-1:-1;;19246:15:17;19229:142;19263:5;;19229:142;;19306:54;19318:7;19326:1;19318:10;;;;;;;;;;;;;;19330:4;19339:1;19335;:5;19330:11;;;;;;;;;;;;;;19343:4;19348:1;19343:7;;;;;;;;;;;;;;19352;19306:11;:54::i;:::-;19289:7;19301:1;19297;:5;19289:14;;;;;;;;;;;;;;;;;:71;-1:-1:-1;;19270:3:17;19229:142;;580:347;655:14;671;715:6;-1:-1:-1;;;;;705:16:17;:6;-1:-1:-1;;;;;705:16:17;;;697:67;;;;-1:-1:-1;;;697:67:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;802:6;-1:-1:-1;;;;;793:15:17;:6;-1:-1:-1;;;;;793:15:17;;:53;;831:6;839;793:53;;;812:6;820;793:53;774:72;;-1:-1:-1;774:72:17;-1:-1:-1;;;;;;864:20:17;;856:64;;;;;-1:-1:-1;;;856:64:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;580:347;;;;;:::o;652:438:21:-;878:45;;;-1:-1:-1;;;;;878:45:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;878:45:21;-1:-1:-1;;;878:45:21;;;867:57;;;;832:12;;;;867:10;;;;878:45;867:57;;;878:45;867:57;;878:45;867:57;;;;;;;;;;-1:-1:-1;;867:57:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;831:93;;;;955:7;:57;;;;-1:-1:-1;967:11:21;;:16;;:44;;;998:4;987:24;;;;;;;;;;;;;;;-1:-1:-1;987:24:21;967:44;934:149;;;;-1:-1:-1;;;934:149:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5659:3401:17;5812:17;5860:1;5849:8;:12;5841:69;;;;-1:-1:-1;;;5841:69:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5920:17;5947:18;5975:23;6008:12;6030;6103:14;6123:29;6134:7;6143:8;6123:10;:29::i;:::-;6102:50;;;6187:6;-1:-1:-1;;;;;6176:17:17;:7;-1:-1:-1;;;;;6176:17:17;;6166:27;;6239:39;6251:7;6260;6269:8;6239:11;:39::i;:::-;6207:71;;;;;;;;;;;;5659:3401;6298:19;6327:11;6398;6423:37;6518:4;-1:-1:-1;;;;;6502:37:17;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6502:39:17;;;;;;;;;;;;-1:-1:-1;6474:67:17;;;-1:-1:-1;6502:39:17;-1:-1:-1;6573:25:17;:8;6586:5;:11;;;6573:12;:25::i;:::-;6555:43;-1:-1:-1;6652:35:17;6638:10;:49;;;;;;;;;6637:142;;;-1:-1:-1;6727:39:17;6713:10;:53;;;;;;;;;:65;;;;;6771:7;6770:8;6713:65;6637:232;;;-1:-1:-1;6818:39:17;6804:10;:53;;;;;;;;;:64;;;;;6861:7;6804:64;6612:327;;;;-1:-1:-1;;;6612:327:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5659:3401;;7072:6;7068:1638;;;7095:14;7111;7145:4;-1:-1:-1;;;;;7129:31:17;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7129:33:17;;;;;;;;;-1:-1:-1;7129:33:17;-1:-1:-1;7176:13:17;7192:137;7219:96;7129:33;;7248:7;:32;;7270:10;7248:32;;;7258:9;7248:32;7282:7;:32;;7305:9;7282:32;;;7292:10;7282:32;7219:12;:96::i;:::-;7192:9;:137::i;:::-;7176:153;-1:-1:-1;7604:16:17;7176:153;7614:5;7604:9;:16::i;:::-;7559:41;7579:20;:9;7593:5;7579:13;:20::i;:::-;7559:15;;:19;:41::i;:::-;:61;7555:1141;;7743:55;7765:7;:25;;7784:6;7765:25;;;7775:6;7765:25;7792:5;7743:21;:55::i;:::-;7729:69;;8095:5;8083:9;:17;:37;;;;;8114:6;8104;:16;;8083:37;8079:406;;;8272:21;:10;8287:5;8272:14;:21::i;:::-;8260:33;-1:-1:-1;8333:54:17;8353:33;8380:5;8354:20;:5;8364:9;8354;:20::i;:::-;8353:26;;:33::i;:::-;8333:15;;:19;:54::i;:::-;8315:72;;8421:5;8409:17;;8461:5;8448:18;;8079:406;7555:1141;;;8626:55;8648:7;:25;;8667:6;8648:25;;;8658:6;8675:5;8626:21;:55::i;:::-;8612:69;;7555:1141;7068:1638;;;;8715:17;8735:48;8755:27;:10;8770:11;8755:14;:27::i;:::-;8735:15;;:19;:48::i;:::-;8715:68;-1:-1:-1;8793:19:17;8815:60;8859:15;8815:39;8848:5;8816:26;:9;8830:11;8816:13;:26::i;8815:39::-;:43;;:60::i;:::-;8793:82;;8885:25;8925:11;8913:9;:23;;;;;;8885:51;;8979:10;8959:17;:30;8958:95;;9021:32;:17;9043:9;9021:21;:32::i;:::-;8958:95;;;8993:25;:10;9008:9;8993:14;:25::i;:::-;8946:107;5659:3401;-1:-1:-1;;;;;;;;;;;;;;;5659:3401:17:o;1096:486:21:-;1360:51;;;-1:-1:-1;;;;;1360:51:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1360:51:21;-1:-1:-1;;;1360:51:21;;;1349:63;;;;1314:12;;;;1349:10;;;;1360:51;1349:63;;;1360:51;1349:63;;1360:51;1349:63;;;;;;;;;;-1:-1:-1;;1349:63:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1313:99;;;;1443:7;:57;;;;-1:-1:-1;1455:11:21;;:16;;:44;;;1486:4;1475:24;;;;;;;;;;;;;;;-1:-1:-1;1475:24:21;1455:44;1422:153;;;;-1:-1:-1;;;1422:153:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1096:486;;;;;;:::o;212:434::-;436:45;;;-1:-1:-1;;;;;436:45:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;436:45:21;-1:-1:-1;;;436:45:21;;;425:57;;;;390:12;;;;425:10;;;;436:45;425:57;;;436:45;425:57;;436:45;425:57;;;;;;;;;;-1:-1:-1;;425:57:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;389:93;;;;513:7;:57;;;;-1:-1:-1;525:11:21;;:16;;:44;;;556:4;545:24;;;;;;;;;;;;;;;-1:-1:-1;545:24:21;525:44;492:147;;;;-1:-1:-1;;;492:147:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9646:3327:17;9799:16;9847:1;9835:9;:13;9827:70;;;;-1:-1:-1;;;9827:70:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9908:17;9935:18;9963:19;9992:11;10013:12;10085:11;10110:14;10138;10225;10245:29;10256:7;10265:8;10245:10;:29::i;:::-;-1:-1:-1;;;;;;10302:17:17;;;;;;;-1:-1:-1;10405:12:17;;-1:-1:-1;10467:39:17;10479:7;10302;10497:8;10467:11;:39::i;:::-;10435:71;;;;;;;;;;;;10524:37;10623:4;-1:-1:-1;;;;;10607:37:17;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10607:39:17;;;;;;;;;;;10579:67;;;;;-1:-1:-1;10607:39:17;-1:-1:-1;10607:39:17;-1:-1:-1;10708:35:17;10694:10;:49;;;;;;;;;10693:146;;;-1:-1:-1;10787:39:17;10773:10;:53;;;;;;;;;:65;;;;;10831:7;10830:8;10773:65;10693:240;;;-1:-1:-1;10882:39:17;10868:10;:53;;;;;;;;;:64;;;;;10925:7;10868:64;10664:347;;;;-1:-1:-1;;;10664:347:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11064:4;-1:-1:-1;;;;;11048:31:17;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11048:33:17;;;;;;;;;-1:-1:-1;11048:33:17;-1:-1:-1;;11109:1602:17;;;-1:-1:-1;11109:1602:17;;11139:13;11155:145;11186:96;11199:6;11207;11215:7;:32;;11237:10;11215:32;;;11225:9;11215:32;11249:7;:32;;11272:9;11249:32;;;11259:10;11186:12;:96::i;11155:145::-;11139:161;;11469:5;11440:25;11455:9;11440:10;:14;;:25;;;;:::i;:::-;:34;11436:1261;;11606:55;11628:7;:25;;11647:6;11628:25;;11606:55;11592:69;;11436:1261;;;11816:55;11838:7;:25;;11857:6;11838:25;;11816:55;11802:69;;12183:5;12170:10;:18;:38;;;;;12202:6;12192;:16;;12170:38;12166:513;;;12367:31;12392:5;12367:20;:5;12377:9;12367;:20::i;:31::-;12356:42;-1:-1:-1;12533:36:17;12547:21;:10;12562:5;12547:14;:21::i;:::-;12533:9;;:13;:36::i;:::-;12521:48;;12608:5;12595:18;;12651:5;12639:17;;12166:513;11109:1602;;-1:-1:-1;12730:17:17;;-1:-1:-1;12750:54:17;;-1:-1:-1;12798:5:17;12750:43;12783:9;12750:43;12751:9;12765:11;12751:13;:26::i;12750:54::-;12730:74;-1:-1:-1;12814:19:17;12836:44;12870:9;12837:27;:10;12852:11;12837:14;:27::i;:::-;12836:33;;:44::i;:::-;12814:66;;12901:65;12964:1;12902:56;12954:3;12946:5;:11;12902:39;12928:11;12916:9;:23;;;;;12902:8;;12916:23;;12902:12;:39::i;:::-;:43;;:56::i;12901:65::-;12890:76;9646:3327;-1:-1:-1;;;;;;;;;;;;9646:3327:17:o;2327:539::-;2487:16;2517;2547:12;2585:14;2605:26;2616:6;2624;2605:10;:26::i;:::-;2584:47;;;2648:32;2656:7;2665:6;2673;2648:7;:32::i;:::-;2641:39;;2691:16;2709;2745:4;-1:-1:-1;;;;;2729:33:17;;:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2729:35:17;;;;;;;;;-1:-1:-1;2729:35:17;-1:-1:-1;;;;;;2797:16:17;;;;;;;:62;;2840:8;2850;2797:62;;;2817:8;2827;2797:62;2774:85;;;;-1:-1:-1;2327:539:17;;-1:-1:-1;2327:539:17;;-1:-1:-1;;;;;;2327:539:17:o;471:149:20:-;529:9;558:6;;;:30;;-1:-1:-1;;573:5:20;;;587:1;582;573:5;582:1;568:15;;;;;:20;558:30;550:63;;;;;-1:-1:-1;;;550:63:20;;;;;;;;;;;;-1:-1:-1;;;550:63:20;;;;;;;;;;;;;;;471:149;;;;:::o;4057:489:17:-;4208:9;4229:13;4257:8;4246;:19;4245:53;;4285:13;:6;4296:1;4285:10;:13::i;:::-;4245:53;;;4269:13;:6;4280:1;4269:10;:13::i;:::-;4229:69;-1:-1:-1;4308:13:17;4324:19;4341:1;4324:12;4229:69;4334:1;4324:9;:12::i;:19::-;4308:35;-1:-1:-1;4366:12:17;4381:51;4419:12;4308:35;4429:1;4419:9;:12::i;:::-;4381:33;4391:22;:8;4404;4391:12;:22::i;:::-;4381:5;;:9;:33::i;:51::-;4366:66;-1:-1:-1;4538:1:17;4366:66;4474:54;4494:33;4521:5;4494:22;:8;4507;4494:12;:22::i;:33::-;4490:1;4484:4;:7;:43;4474:9;:54::i;:::-;:61;4473:66;;4057:489;-1:-1:-1;;;;;;;;4057:489:17:o;349:301:18:-;397:9;426:1;422;:5;418:226;;;-1:-1:-1;447:1:18;482;478;474:5;;:9;497:89;508:1;504;:5;497:89;;;533:1;529:5;;570:1;565;561;557;:5;;;;;;:9;556:15;;;;;;552:19;;497:89;;;418:226;;;;606:6;;602:42;;-1:-1:-1;632:1:18;602:42;349:301;;;:::o;188:135:20:-;280:5;;;275:16;;;;267:49;;;;;-1:-1:-1;;;267:49:20;;;;;;;;;;;;-1:-1:-1;;;267:49:20;;;;;;;;;;;;;;4938:143:17;5024:7;5050:24;-1:-1:-1;;5051:10:17;;5067:6;5050:16;:24::i;:::-;5043:31;4938:143;-1:-1:-1;;;4938:143:17:o;329:136:20:-;421:5;;;416:16;;;;408:50;;;;;-1:-1:-1;;;408:50:20;;;;;;;;;;;;-1:-1:-1;;;408:50:20;;;;;;;;;;;;;;1082:130;1140:7;1166:39;1170:1;1173;1166:39;;;;;;;;;;;;;;;;;1810:7;1844:12;1837:5;1829:28;;;;-1:-1:-1;;;1829:28:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1867:9;1883:1;1879;:5;;;;;;;1694:302;-1:-1:-1;;;;;1694:302:20:o;14:404:24:-;;;147:3;140:4;132:6;128:17;124:27;114:2;;172:8;162;155:26;114:2;-1:-1:-1;202:20:24;;245:18;234:30;;231:2;;;284:8;274;267:26;231:2;328:4;320:6;316:17;304:29;;391:3;384:4;376;368:6;364:17;356:6;352:30;348:41;345:50;342:2;;;408:1;405;398:12;423:158;491:20;;551:4;540:16;;530:27;;520:2;;571:1;568;561:12;586:259;;698:2;686:9;677:7;673:23;669:32;666:2;;;719:6;711;704:22;666:2;763:9;750:23;782:33;809:5;782:33;:::i;850:263::-;;973:2;961:9;952:7;948:23;944:32;941:2;;;994:6;986;979:22;941:2;1031:9;1025:16;1050:33;1077:5;1050:33;:::i;1118:402::-;;;1247:2;1235:9;1226:7;1222:23;1218:32;1215:2;;;1268:6;1260;1253:22;1215:2;1312:9;1299:23;1331:33;1358:5;1331:33;:::i;:::-;1383:5;-1:-1:-1;1440:2:24;1425:18;;1412:32;1453:35;1412:32;1453:35;:::i;:::-;1507:7;1497:17;;;1205:315;;;;;:::o;1525:821::-;;;;;;;;1739:3;1727:9;1718:7;1714:23;1710:33;1707:2;;;1761:6;1753;1746:22;1707:2;1805:9;1792:23;1824:33;1851:5;1824:33;:::i;:::-;1876:5;-1:-1:-1;1933:2:24;1918:18;;1905:32;1946:35;1905:32;1946:35;:::i;:::-;2000:7;-1:-1:-1;2054:2:24;2039:18;;2026:32;;-1:-1:-1;2105:2:24;2090:18;;2077:32;;-1:-1:-1;2156:3:24;2141:19;;2128:33;;-1:-1:-1;2213:3:24;2198:19;;2185:33;2227:35;2185:33;2227:35;:::i;:::-;2281:7;2271:17;;;2335:3;2324:9;2320:19;2307:33;2297:43;;1697:649;;;;;;;;;;:::o;2351:1172::-;;;;;;;;;;;;2629:3;2617:9;2608:7;2604:23;2600:33;2597:2;;;2651:6;2643;2636:22;2597:2;2695:9;2682:23;2714:33;2741:5;2714:33;:::i;:::-;2766:5;-1:-1:-1;2823:2:24;2808:18;;2795:32;2836:35;2795:32;2836:35;:::i;:::-;2890:7;-1:-1:-1;2944:2:24;2929:18;;2916:32;;-1:-1:-1;2995:2:24;2980:18;;2967:32;;-1:-1:-1;3046:3:24;3031:19;;3018:33;;-1:-1:-1;3103:3:24;3088:19;;3075:33;3117:35;3075:33;3117:35;:::i;:::-;3171:7;-1:-1:-1;3225:3:24;3210:19;;3197:33;;-1:-1:-1;3282:3:24;3267:19;;3254:33;3296:32;3254:33;3296:32;:::i;:::-;3347:7;-1:-1:-1;3373:39:24;3407:3;3392:19;;3373:39;:::i;:::-;3363:49;;3459:3;3448:9;3444:19;3431:33;3421:43;;3512:3;3501:9;3497:19;3484:33;3473:44;;2587:936;;;;;;;;;;;;;;:::o;3528:890::-;;;;;;;;;3759:3;3747:9;3738:7;3734:23;3730:33;3727:2;;;3781:6;3773;3766:22;3727:2;3825:9;3812:23;3844:33;3871:5;3844:33;:::i;:::-;3896:5;-1:-1:-1;3953:2:24;3938:18;;3925:32;3966:35;3925:32;3966:35;:::i;:::-;4020:7;-1:-1:-1;4074:2:24;4059:18;;4046:32;;-1:-1:-1;4125:2:24;4110:18;;4097:32;;-1:-1:-1;4176:3:24;4161:19;;4148:33;;-1:-1:-1;4228:3:24;4213:19;;4200:33;;-1:-1:-1;4285:3:24;4270:19;;4257:33;4299:35;4257:33;4299:35;:::i;:::-;4353:7;4343:17;;;4407:3;4396:9;4392:19;4379:33;4369:43;;3717:701;;;;;;;;;;;:::o;4423:677::-;;;;;;;4620:3;4608:9;4599:7;4595:23;4591:33;4588:2;;;4642:6;4634;4627:22;4588:2;4686:9;4673:23;4705:33;4732:5;4705:33;:::i;:::-;4757:5;-1:-1:-1;4809:2:24;4794:18;;4781:32;;-1:-1:-1;4860:2:24;4845:18;;4832:32;;-1:-1:-1;4911:2:24;4896:18;;4883:32;;-1:-1:-1;4967:3:24;4952:19;;4939:33;4981:35;4939:33;4981:35;:::i;:::-;5035:7;5025:17;;;5089:3;5078:9;5074:19;5061:33;5051:43;;4578:522;;;;;;;;:::o;5105:1026::-;;;;;;;;;;;5365:3;5353:9;5344:7;5340:23;5336:33;5333:2;;;5387:6;5379;5372:22;5333:2;5431:9;5418:23;5450:33;5477:5;5450:33;:::i;:::-;5502:5;-1:-1:-1;5554:2:24;5539:18;;5526:32;;-1:-1:-1;5605:2:24;5590:18;;5577:32;;-1:-1:-1;5656:2:24;5641:18;;5628:32;;-1:-1:-1;5712:3:24;5697:19;;5684:33;5726:35;5684:33;5726:35;:::i;:::-;5780:7;-1:-1:-1;5834:3:24;5819:19;;5806:33;;-1:-1:-1;5891:3:24;5876:19;;5863:33;5905:32;5863:33;5905:32;:::i;:::-;5956:7;-1:-1:-1;5982:39:24;6016:3;6001:19;;5982:39;:::i;:::-;5972:49;;6068:3;6057:9;6053:19;6040:33;6030:43;;6120:3;6109:9;6105:19;6092:33;6082:43;;5323:808;;;;;;;;;;;;;:::o;6136:257::-;;6256:2;6244:9;6235:7;6231:23;6227:32;6224:2;;;6277:6;6269;6262:22;6224:2;6314:9;6308:16;6333:30;6357:5;6333:30;:::i;6398:194::-;;6521:2;6509:9;6500:7;6496:23;6492:32;6489:2;;;6542:6;6534;6527:22;6489:2;-1:-1:-1;6570:16:24;;6479:113;-1:-1:-1;6479:113:24:o;6597:737::-;;;;;;6795:3;6783:9;6774:7;6770:23;6766:33;6763:2;;;6817:6;6809;6802:22;6763:2;6858:9;6845:23;6835:33;;6919:2;6908:9;6904:18;6891:32;6946:18;6938:6;6935:30;6932:2;;;6983:6;6975;6968:22;6932:2;7027:76;7095:7;7086:6;7075:9;7071:22;7027:76;:::i;:::-;7122:8;;-1:-1:-1;7001:102:24;-1:-1:-1;;7207:2:24;7192:18;;7179:32;7220:33;7179:32;7220:33;:::i;:::-;6753:581;;;;-1:-1:-1;6753:581:24;;7324:2;7309:18;7296:32;;6753:581;-1:-1:-1;;6753:581:24:o;7339:255::-;;;7479:2;7467:9;7458:7;7454:23;7450:32;7447:2;;;7500:6;7492;7485:22;7447:2;-1:-1:-1;;7528:16:24;;7584:2;7569:18;;;7563:25;7528:16;;7563:25;;-1:-1:-1;7437:157:24:o;7599:806::-;;;;;;;7814:3;7802:9;7793:7;7789:23;7785:33;7782:2;;;7836:6;7828;7821:22;7782:2;7877:9;7864:23;7854:33;;7934:2;7923:9;7919:18;7906:32;7896:42;;7989:2;7978:9;7974:18;7961:32;8016:18;8008:6;8005:30;8002:2;;;8053:6;8045;8038:22;8002:2;8097:76;8165:7;8156:6;8145:9;8141:22;8097:76;:::i;:::-;8192:8;;-1:-1:-1;8071:102:24;-1:-1:-1;;8277:2:24;8262:18;;8249:32;8290:33;8249:32;8290:33;:::i;:::-;8342:5;8332:15;;;8394:3;8383:9;8379:19;8366:33;8356:43;;7772:633;;;;;;;;:::o;8410:532::-;;8516:6;8511:3;8504:19;8542:4;8571:2;8566:3;8562:12;8555:19;;8597:5;8620:3;8632:285;8646:6;8643:1;8640:13;8632:285;;;8723:6;8710:20;8743:35;8770:7;8743:35;:::i;:::-;-1:-1:-1;;;;;8803:33:24;8791:46;;8857:12;;;;8892:15;;;;8833:1;8661:9;8632:285;;;-1:-1:-1;8933:3:24;;8494:448;-1:-1:-1;;;;;8494:448:24:o;8947:443::-;;9044:5;9038:12;9071:6;9066:3;9059:19;9097:4;9126:2;9121:3;9117:12;9110:19;;9163:2;9156:5;9152:14;9184:3;9196:169;9210:6;9207:1;9204:13;9196:169;;;9271:13;;9259:26;;9305:12;;;;9340:15;;;;9232:1;9225:9;9196:169;;9395:203;-1:-1:-1;;;;;9559:32:24;;;;9541:51;;9529:2;9514:18;;9496:102::o;9819:686::-;-1:-1:-1;;;;;10202:15:24;;;10184:34;;10254:15;;;;10249:2;10234:18;;10227:43;10301:2;10286:18;;10279:34;;;;10344:2;10329:18;;10322:34;;;;10405:4;10393:17;10387:3;10372:19;;10365:46;10164:3;10427:19;;10420:35;10486:3;10471:19;;10464:35;;;;10133:3;10118:19;;10100:405::o;10510:383::-;-1:-1:-1;;;;;10776:15:24;;;10758:34;;10828:15;;;;10823:2;10808:18;;10801:43;10875:2;10860:18;;10853:34;;;;10708:2;10693:18;;10675:218::o;10898:528::-;-1:-1:-1;;;;;11213:15:24;;;11195:34;;11265:15;;;11260:2;11245:18;;11238:43;11317:15;;;;11312:2;11297:18;;11290:43;11364:2;11349:18;;11342:34;;;;11407:3;11392:19;;11385:35;;;;11144:3;11129:19;;11111:315::o;11431:591::-;-1:-1:-1;;;;;11774:15:24;;;11756:34;;11826:15;;;;11821:2;11806:18;;11799:43;11873:2;11858:18;;11851:34;;;;11916:2;11901:18;;11894:34;11959:3;11944:19;;11937:35;11736:3;11988:19;;11981:35;;;;11705:3;11690:19;;11672:350::o;12027:274::-;-1:-1:-1;;;;;12219:32:24;;;;12201:51;;12283:2;12268:18;;12261:34;12189:2;12174:18;;12156:145::o;12306:294::-;;12495:2;12484:9;12477:21;12515:79;12590:2;12579:9;12575:18;12567:6;12559;12515:79;:::i;:::-;12507:87;12467:133;-1:-1:-1;;;;12467:133:24:o;12605:267::-;;12784:2;12773:9;12766:21;12804:62;12862:2;12851:9;12847:18;12839:6;12804:62;:::i;12877:504::-;;13144:2;13133:9;13126:21;13170:62;13228:2;13217:9;13213:18;13205:6;13170:62;:::i;:::-;13280:9;13272:6;13268:22;13263:2;13252:9;13248:18;13241:50;13308:67;13368:6;13360;13352;13308:67;:::i;:::-;13300:75;13116:265;-1:-1:-1;;;;;;13116:265:24:o;13386:328::-;13588:2;13570:21;;;13627:1;13607:18;;;13600:29;-1:-1:-1;;;13660:2:24;13645:18;;13638:35;13705:2;13690:18;;13560:154::o;13719:404::-;13921:2;13903:21;;;13960:2;13940:18;;;13933:30;13999:34;13994:2;13979:18;;13972:62;-1:-1:-1;;;14065:2:24;14050:18;;14043:38;14113:3;14098:19;;13893:230::o;14128:408::-;14330:2;14312:21;;;14369:2;14349:18;;;14342:30;14408:34;14403:2;14388:18;;14381:62;-1:-1:-1;;;14474:2:24;14459:18;;14452:42;14526:3;14511:19;;14302:234::o;14541:354::-;14743:2;14725:21;;;14782:2;14762:18;;;14755:30;14821:32;14816:2;14801:18;;14794:60;14886:2;14871:18;;14715:180::o;14900:349::-;15102:2;15084:21;;;15141:2;15121:18;;;15114:30;15180:27;15175:2;15160:18;;15153:55;15240:2;15225:18;;15074:175::o;15254:177::-;15400:25;;;15388:2;15373:18;;15355:76::o;15436:248::-;15610:25;;;15666:2;15651:18;;15644:34;15598:2;15583:18;;15565:119::o;15689:319::-;15891:25;;;15947:2;15932:18;;15925:34;;;;15990:2;15975:18;;15968:34;15879:2;15864:18;;15846:162::o;16013:133::-;-1:-1:-1;;;;;16090:31:24;;16080:42;;16070:2;;16136:1;16133;16126:12;16070:2;16060:86;:::o;16151:120::-;16239:5;16232:13;16225:21;16218:5;16215:32;16205:2;;16261:1;16258;16251:12
Swarm Source
ipfs://1d47bb6aa4c4e5a635ca01716e6be81c6af6f3e867a84fc2495526c9765ca442
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.