More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,578,799 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Swap Exact Token... | 134890312 | 1 min ago | IN | 0 ETH | 0.00000226006 | ||||
Remove Liquidity | 134890206 | 4 mins ago | IN | 0 ETH | 0.00000393738 | ||||
Swap Exact Token... | 134890168 | 6 mins ago | IN | 0 ETH | 0.000004112898 | ||||
Add Liquidity | 134889666 | 22 mins ago | IN | 0 ETH | 0.000005734774 | ||||
Add Liquidity | 134889617 | 24 mins ago | IN | 0 ETH | 0.000004432287 | ||||
Swap Exact Token... | 134889557 | 26 mins ago | IN | 0 ETH | 0.000004078381 | ||||
Remove Liquidity | 134889327 | 34 mins ago | IN | 0 ETH | 0.000004264166 | ||||
Swap Exact Token... | 134889271 | 36 mins ago | IN | 0 ETH | 0.000004606667 | ||||
Swap Exact Token... | 134889184 | 38 mins ago | IN | 0 ETH | 0.000004340365 | ||||
Add Liquidity | 134889021 | 44 mins ago | IN | 0 ETH | 0.000005319617 | ||||
Remove Liquidity | 134888927 | 47 mins ago | IN | 0 ETH | 0.000005668952 | ||||
Add Liquidity | 134888619 | 57 mins ago | IN | 0 ETH | 0.000004303217 | ||||
Swap Exact Token... | 134888222 | 1 hr ago | IN | 0 ETH | 0.000003079434 | ||||
Swap Exact Token... | 134888045 | 1 hr ago | IN | 0 ETH | 0.000003550189 | ||||
Swap Exact Token... | 134887904 | 1 hr ago | IN | 0 ETH | 0.000005089021 | ||||
Swap Exact Token... | 134887454 | 1 hr ago | IN | 0 ETH | 0.000003098623 | ||||
Swap Exact Token... | 134887383 | 1 hr ago | IN | 0 ETH | 0.000003697271 | ||||
Swap Exact Token... | 134887304 | 1 hr ago | IN | 0 ETH | 0.00000254159 | ||||
Swap Exact Token... | 134887160 | 1 hr ago | IN | 0 ETH | 0.000002566664 | ||||
Swap Exact Token... | 134887116 | 1 hr ago | IN | 0 ETH | 0.000002687184 | ||||
Swap Exact Token... | 134886990 | 1 hr ago | IN | 0 ETH | 0.000002294284 | ||||
Swap Exact Token... | 134886696 | 2 hrs ago | IN | 0 ETH | 0.000003816835 | ||||
Swap Exact Token... | 134886099 | 2 hrs ago | IN | 0 ETH | 0.000002222101 | ||||
Swap Exact Token... | 134885944 | 2 hrs ago | IN | 0 ETH | 0.000002651137 | ||||
Add Liquidity | 134885939 | 2 hrs ago | IN | 0 ETH | 0.000002126311 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
134875339 | 8 hrs ago | 0.0009975 ETH | ||||
134875339 | 8 hrs ago | 0.0009975 ETH | ||||
134869527 | 11 hrs ago | 0.000000000367175 ETH | ||||
134869527 | 11 hrs ago | 0.010599999632824 ETH | ||||
134868241 | 12 hrs ago | 0.061207276964681 ETH | ||||
134858443 | 17 hrs ago | 1.857438368207062 ETH | ||||
134855058 | 19 hrs ago | 0.00000000016763 ETH | ||||
134855058 | 19 hrs ago | 0.002761308504194 ETH | ||||
134844861 | 25 hrs ago | 0.007014246565236 ETH | ||||
134844861 | 25 hrs ago | 0.007014246565236 ETH | ||||
134844792 | 25 hrs ago | 0.676858701544741 ETH | ||||
134841812 | 26 hrs ago | 0.000025971084718 ETH | ||||
134841812 | 26 hrs ago | 0.032974028915281 ETH | ||||
134841761 | 26 hrs ago | 0.472205440699682 ETH | ||||
134834347 | 31 hrs ago | 13.801208133362586 ETH | ||||
134820749 | 38 hrs ago | 0.000697989659819 ETH | ||||
134815291 | 41 hrs ago | 0.000498547405201 ETH | ||||
134809455 | 44 hrs ago | 0.202029899843997 ETH | ||||
134808776 | 45 hrs ago | 0.044417578918365 ETH | ||||
134780811 | 2 days ago | 1 wei | ||||
134780811 | 2 days ago | 0.002299999999999 ETH | ||||
134778501 | 2 days ago | 0.000000000632639 ETH | ||||
134776948 | 2 days ago | 1 wei | ||||
134776948 | 2 days ago | 6.999999999999999 ETH | ||||
134771506 | 2 days ago | 0.002085561614778 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Router
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IPool} from "./interfaces/IPool.sol"; import {IPoolFactory} from "./interfaces/factories/IPoolFactory.sol"; import {IPairFactoryV1} from "./interfaces/v1/IPairFactoryV1.sol"; import {IRouter} from "./interfaces/IRouter.sol"; import {IVoter} from "./interfaces/IVoter.sol"; import {IGauge} from "./interfaces/IGauge.sol"; import {IFactoryRegistry} from "./interfaces/factories/IFactoryRegistry.sol"; import {IWETH} from "./interfaces/IWETH.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; /// @title Velodrome V2 Router /// @author velodrome.finance, @pegahcarter /// @notice Router allows routes through any pools created by any factory adhering to univ2 interface. /// @dev Zapping and swapping support both v1 and v2. Adding liquidity supports v2 only. contract Router is IRouter, ERC2771Context { using SafeERC20 for IERC20; address public immutable factoryRegistry; address public immutable v1Factory; /// @dev v2 default pair factory address public immutable defaultFactory; address public immutable voter; IWETH public immutable weth; uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3; /// @dev Represents Ether. Used by zapper to determine whether to return assets as ETH/WETH. address public constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; modifier ensure(uint256 deadline) { _ensureDeadline(deadline); _; } function _ensureDeadline(uint256 deadline) internal view { if (deadline < block.timestamp) revert Expired(); } constructor( address _forwarder, address _factoryRegistry, address _v1Factory, address _factory, address _voter, address _weth ) ERC2771Context(_forwarder) { factoryRegistry = _factoryRegistry; v1Factory = _v1Factory; defaultFactory = _factory; voter = _voter; weth = IWETH(_weth); } receive() external payable { if (msg.sender != address(weth)) revert OnlyWETH(); } /// @inheritdoc IRouter function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) { if (tokenA == tokenB) revert SameAddresses(); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); if (token0 == address(0)) revert ZeroAddress(); } /// @inheritdoc IRouter function pairFor( address tokenA, address tokenB, bool stable, address _factory ) external view returns (address pool) { return poolFor(tokenA, tokenB, stable, _factory); } /// @inheritdoc IRouter function poolFor(address tokenA, address tokenB, bool stable, address _factory) public view returns (address pool) { address _defaultFactory = defaultFactory; address factory = _factory == address(0) ? _defaultFactory : _factory; if (!IFactoryRegistry(factoryRegistry).isPoolFactoryApproved(factory)) revert PoolFactoryDoesNotExist(); address velo = IPoolFactory(_defaultFactory).velo(); address veloV2 = IPoolFactory(_defaultFactory).veloV2(); // Disable routing v2 -> v1 velo if ((tokenA == veloV2) && (tokenB == velo)) revert ConversionFromV2ToV1VeloProhibited(); // Override for sink converter if ((tokenA == velo) && (tokenB == veloV2)) { return IPoolFactory(_defaultFactory).sinkConverter(); } (address token0, address token1) = sortTokens(tokenA, tokenB); if (factory != v1Factory) { bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); pool = Clones.predictDeterministicAddress(IPoolFactory(factory).implementation(), salt, factory); } else { // backwards compatible with v1 bytes32 pairCodeHash = IPairFactoryV1(factory).pairCodeHash(); pool = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256(abi.encodePacked(token0, token1, stable)), pairCodeHash // init code hash ) ) ) ) ); } } /// @dev given some amount of an asset and pool reserves, returns an equivalent amount of the other asset /// @dev this only accounts for volatile pools and may return insufficient liquidity for stable pools function quoteLiquidity( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { if (amountA == 0) revert InsufficientAmount(); if (reserveA == 0 || reserveB == 0) revert InsufficientLiquidity(); amountB = (amountA * reserveB) / reserveA; } /// @inheritdoc IRouter function getReserves( address tokenA, address tokenB, bool stable, address _factory ) public view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = IPool(poolFor(tokenA, tokenB, stable, _factory)).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } /// @inheritdoc IRouter function getAmountsOut(uint256 amountIn, Route[] memory routes) public view returns (uint256[] memory amounts) { if (routes.length < 1) revert InvalidPath(); amounts = new uint256[](routes.length + 1); amounts[0] = amountIn; uint256 _length = routes.length; for (uint256 i = 0; i < _length; i++) { address factory = routes[i].factory == address(0) ? defaultFactory : routes[i].factory; // default to v2 address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable, factory); if (IPoolFactory(factory).isPair(pool)) { amounts[i + 1] = IPool(pool).getAmountOut(amounts[i], routes[i].from); } } } /// @inheritdoc IRouter function quoteAddLiquidity( address tokenA, address tokenB, bool stable, address _factory, uint256 amountADesired, uint256 amountBDesired ) public view returns (uint256 amountA, uint256 amountB, uint256 liquidity) { address _pool = IPoolFactory(_factory).getPair(tokenA, tokenB, stable); (uint256 reserveA, uint256 reserveB) = (0, 0); uint256 _totalSupply = 0; if (_pool != address(0)) { _totalSupply = IERC20(_pool).totalSupply(); (reserveA, reserveB) = getReserves(tokenA, tokenB, stable, _factory); } if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); liquidity = Math.sqrt(amountA * amountB) - MINIMUM_LIQUIDITY; } else { uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { (amountA, amountB) = (amountADesired, amountBOptimal); liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB); } else { uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA); (amountA, amountB) = (amountAOptimal, amountBDesired); liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB); } } } /// @inheritdoc IRouter function quoteRemoveLiquidity( address tokenA, address tokenB, bool stable, address _factory, uint256 liquidity ) public view returns (uint256 amountA, uint256 amountB) { address _pool = IPoolFactory(_factory).getPair(tokenA, tokenB, stable); if (_pool == address(0)) { return (0, 0); } (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, _factory); uint256 _totalSupply = IERC20(_pool).totalSupply(); amountA = (liquidity * reserveA) / _totalSupply; // using balances ensures pro-rata distribution amountB = (liquidity * reserveB) / _totalSupply; // using balances ensures pro-rata distribution } function _addLiquidity( address tokenA, address tokenB, bool stable, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin ) internal returns (uint256 amountA, uint256 amountB) { if (amountADesired < amountAMin) revert InsufficientAmountADesired(); if (amountBDesired < amountBMin) revert InsufficientAmountBDesired(); // create the pool if it doesn't exist yet address _pool = IPoolFactory(defaultFactory).getPair(tokenA, tokenB, stable); if (_pool == address(0)) { _pool = IPoolFactory(defaultFactory).createPair(tokenA, tokenB, stable); } (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, defaultFactory); if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); } else { uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { if (amountBOptimal < amountBMin) revert InsufficientAmountB(); (amountA, amountB) = (amountADesired, amountBOptimal); } else { uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); if (amountAOptimal < amountAMin) revert InsufficientAmountA(); (amountA, amountB) = (amountAOptimal, amountBDesired); } } } /// @inheritdoc IRouter function addLiquidity( address tokenA, address tokenB, bool stable, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) public ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) { (amountA, amountB) = _addLiquidity( tokenA, tokenB, stable, amountADesired, amountBDesired, amountAMin, amountBMin ); address pool = poolFor(tokenA, tokenB, stable, defaultFactory); _safeTransferFrom(tokenA, _msgSender(), pool, amountA); _safeTransferFrom(tokenB, _msgSender(), pool, amountB); liquidity = IPool(pool).mint(to); } /// @inheritdoc IRouter function addLiquidityETH( address token, bool stable, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable ensure(deadline) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) { (amountToken, amountETH) = _addLiquidity( token, address(weth), stable, amountTokenDesired, msg.value, amountTokenMin, amountETHMin ); address pool = poolFor(token, address(weth), stable, defaultFactory); _safeTransferFrom(token, _msgSender(), pool, amountToken); weth.deposit{value: amountETH}(); assert(weth.transfer(pool, amountETH)); liquidity = IPool(pool).mint(to); // refund dust eth, if any if (msg.value > amountETH) _safeTransferETH(_msgSender(), msg.value - amountETH); } // **** REMOVE LIQUIDITY **** /// @inheritdoc IRouter function removeLiquidity( address tokenA, address tokenB, bool stable, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) public ensure(deadline) returns (uint256 amountA, uint256 amountB) { address pool = poolFor(tokenA, tokenB, stable, defaultFactory); IERC20(pool).safeTransferFrom(_msgSender(), pool, liquidity); (uint256 amount0, uint256 amount1) = IPool(pool).burn(to); (address token0, ) = sortTokens(tokenA, tokenB); (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); if (amountA < amountAMin) revert InsufficientAmountA(); if (amountB < amountBMin) revert InsufficientAmountB(); } /// @inheritdoc IRouter function removeLiquidityETH( address token, bool stable, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) public ensure(deadline) returns (uint256 amountToken, uint256 amountETH) { (amountToken, amountETH) = removeLiquidity( token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); _safeTransfer(token, to, amountToken); weth.withdraw(amountETH); _safeTransferETH(to, amountETH); } // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** function removeLiquidityETHSupportingFeeOnTransferTokens( address token, bool stable, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) public ensure(deadline) returns (uint256 amountETH) { (, amountETH) = removeLiquidity( token, address(weth), stable, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); _safeTransfer(token, to, IERC20(token).balanceOf(address(this))); weth.withdraw(amountETH); _safeTransferETH(to, amountETH); } // **** SWAP **** /// @dev requires the initial amount to have already been sent to the first pool function _swap(uint256[] memory amounts, Route[] memory routes, address _to) internal virtual { uint256 _length = routes.length; for (uint256 i = 0; i < _length; i++) { (address token0, ) = sortTokens(routes[i].from, routes[i].to); uint256 amountOut = amounts[i + 1]; (uint256 amount0Out, uint256 amount1Out) = routes[i].from == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0)); address to = i < routes.length - 1 ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable, routes[i + 1].factory) : _to; IPool(poolFor(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory)).swap( amount0Out, amount1Out, to, new bytes(0) ); } } function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { amounts = getAmountsOut(amountIn, routes); if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount(); _safeTransferFrom( routes[0].from, _msgSender(), poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amounts[0] ); _swap(amounts, routes, to); } function swapExactETHForTokens( uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external payable ensure(deadline) returns (uint256[] memory amounts) { if (routes[0].from != address(weth)) revert InvalidPath(); amounts = getAmountsOut(msg.value, routes); if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount(); weth.deposit{value: amounts[0]}(); assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amounts[0])); _swap(amounts, routes, to); } function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { if (routes[routes.length - 1].to != address(weth)) revert InvalidPath(); amounts = getAmountsOut(amountIn, routes); if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount(); _safeTransferFrom( routes[0].from, _msgSender(), poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amounts[0] ); _swap(amounts, routes, address(this)); weth.withdraw(amounts[amounts.length - 1]); _safeTransferETH(to, amounts[amounts.length - 1]); } function UNSAFE_swapExactTokensForTokens( uint256[] memory amounts, Route[] calldata routes, address to, uint256 deadline ) external ensure(deadline) returns (uint256[] memory) { _safeTransferFrom( routes[0].from, _msgSender(), poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amounts[0] ); _swap(amounts, routes, to); return amounts; } // **** SWAP (supporting fee-on-transfer tokens) **** /// @dev requires the initial amount to have already been sent to the first pool function _swapSupportingFeeOnTransferTokens(Route[] memory routes, address _to) internal virtual { uint256 _length = routes.length; for (uint256 i; i < _length; i++) { (address token0, ) = sortTokens(routes[i].from, routes[i].to); address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory); uint256 amountInput; uint256 amountOutput; { // stack too deep (uint256 reserveA, ) = getReserves(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory); // getReserves sorts it for us i.e. reserveA is always for from amountInput = IERC20(routes[i].from).balanceOf(pool) - reserveA; } amountOutput = IPool(pool).getAmountOut(amountInput, routes[i].from); (uint256 amount0Out, uint256 amount1Out) = routes[i].from == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0)); address to = i < routes.length - 1 ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable, routes[i + 1].factory) : _to; IPool(pool).swap(amount0Out, amount1Out, to, new bytes(0)); } } /// @inheritdoc IRouter function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external ensure(deadline) { _safeTransferFrom( routes[0].from, _msgSender(), poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amountIn ); uint256 _length = routes.length - 1; uint256 balanceBefore = IERC20(routes[_length].to).balanceOf(to); _swapSupportingFeeOnTransferTokens(routes, to); if (IERC20(routes[_length].to).balanceOf(to) - balanceBefore < amountOutMin) revert InsufficientOutputAmount(); } /// @inheritdoc IRouter function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external payable ensure(deadline) { if (routes[0].from != address(weth)) revert InvalidPath(); uint256 amountIn = msg.value; weth.deposit{value: amountIn}(); assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amountIn)); uint256 _length = routes.length - 1; uint256 balanceBefore = IERC20(routes[_length].to).balanceOf(to); _swapSupportingFeeOnTransferTokens(routes, to); if (IERC20(routes[_length].to).balanceOf(to) - balanceBefore < amountOutMin) revert InsufficientOutputAmount(); } /// @inheritdoc IRouter function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external ensure(deadline) { if (routes[routes.length - 1].to != address(weth)) revert InvalidPath(); _safeTransferFrom( routes[0].from, _msgSender(), poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amountIn ); _swapSupportingFeeOnTransferTokens(routes, address(this)); uint256 amountOut = weth.balanceOf(address(this)); if (amountOut < amountOutMin) revert InsufficientOutputAmount(); weth.withdraw(amountOut); _safeTransferETH(to, amountOut); } /// @inheritdoc IRouter function zapIn( address tokenIn, uint256 amountInA, uint256 amountInB, Zap calldata zapInPool, Route[] calldata routesA, Route[] calldata routesB, address to, bool stake ) external payable returns (uint256 liquidity) { uint256 amountIn = amountInA + amountInB; address _tokenIn = tokenIn; uint256 value = msg.value; if (tokenIn == ETHER) { if (amountIn != value) revert InvalidAmountInForETHDeposit(); _tokenIn = address(weth); weth.deposit{value: value}(); } else { if (value != 0) revert InvalidTokenInForETHDeposit(); _safeTransferFrom(_tokenIn, _msgSender(), address(this), amountIn); } _zapSwap(_tokenIn, amountInA, amountInB, zapInPool, routesA, routesB); _zapInLiquidity(zapInPool); address pool = poolFor(zapInPool.tokenA, zapInPool.tokenB, zapInPool.stable, zapInPool.factory); if (stake) { liquidity = IPool(pool).mint(address(this)); address gauge = IVoter(voter).gauges(pool); IERC20(pool).safeApprove(address(gauge), liquidity); IGauge(gauge).deposit(liquidity, to); IERC20(pool).safeApprove(address(gauge), 0); } else { liquidity = IPool(pool).mint(to); } _returnAssets(tokenIn); _returnAssets(zapInPool.tokenA); _returnAssets(zapInPool.tokenB); } /// @dev Handles swap leg of zap in (i.e. convert tokenIn into tokenA and tokenB). function _zapSwap( address tokenIn, uint256 amountInA, uint256 amountInB, Zap calldata zapInPool, Route[] calldata routesA, Route[] calldata routesB ) internal { address tokenA = zapInPool.tokenA; address tokenB = zapInPool.tokenB; bool stable = zapInPool.stable; address factory = zapInPool.factory; address pool = poolFor(tokenA, tokenB, stable, factory); { (uint256 reserve0, uint256 reserve1, ) = IPool(pool).getReserves(); if (reserve0 <= MINIMUM_LIQUIDITY || reserve1 <= MINIMUM_LIQUIDITY) revert PoolDoesNotExist(); } if (tokenIn != tokenA) { if (routesA[routesA.length - 1].to != tokenA) revert InvalidRouteA(); _internalSwap(tokenIn, amountInA, zapInPool.amountOutMinA, routesA); } if (tokenIn != tokenB) { if (routesB[routesB.length - 1].to != tokenB) revert InvalidRouteB(); _internalSwap(tokenIn, amountInB, zapInPool.amountOutMinB, routesB); } } /// @dev Handles liquidity adding component of zap in. function _zapInLiquidity(Zap calldata zapInPool) internal { address tokenA = zapInPool.tokenA; address tokenB = zapInPool.tokenB; bool stable = zapInPool.stable; address factory = zapInPool.factory; address pool = poolFor(tokenA, tokenB, stable, factory); (uint256 amountA, uint256 amountB) = _quoteZapLiquidity( tokenA, tokenB, stable, factory, IERC20(tokenA).balanceOf(address(this)), IERC20(tokenB).balanceOf(address(this)), zapInPool.amountAMin, zapInPool.amountBMin ); _safeTransfer(tokenA, pool, amountA); _safeTransfer(tokenB, pool, amountB); } /// @dev Similar to _addLiquidity. Assumes a pool exists, and accepts a factory argument. function _quoteZapLiquidity( address tokenA, address tokenB, bool stable, address _factory, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin ) internal view returns (uint256 amountA, uint256 amountB) { if (amountADesired < amountAMin) revert InsufficientAmountADesired(); if (amountBDesired < amountBMin) revert InsufficientAmountBDesired(); (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, _factory); if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); } else { uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { if (amountBOptimal < amountBMin) revert InsufficientAmountB(); (amountA, amountB) = (amountADesired, amountBOptimal); } else { uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); if (amountAOptimal < amountAMin) revert InsufficientAmountA(); (amountA, amountB) = (amountAOptimal, amountBDesired); } } } /// @dev Handles swaps internally for zaps. function _internalSwap(address tokenIn, uint256 amountIn, uint256 amountOutMin, Route[] memory routes) internal { uint256[] memory amounts = getAmountsOut(amountIn, routes); if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount(); address pool = poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory); _safeTransfer(tokenIn, pool, amountIn); _swap(amounts, routes, address(this)); } /// @inheritdoc IRouter function zapOut( address tokenOut, uint256 liquidity, Zap calldata zapOutPool, Route[] calldata routesA, Route[] calldata routesB ) external { address tokenA = zapOutPool.tokenA; address tokenB = zapOutPool.tokenB; address _tokenOut = (tokenOut == ETHER) ? address(weth) : tokenOut; _zapOutLiquidity(liquidity, zapOutPool); uint256 balance; if (tokenA != _tokenOut) { balance = IERC20(tokenA).balanceOf(address(this)); if (routesA[routesA.length - 1].to != _tokenOut) revert InvalidRouteA(); _internalSwap(tokenA, balance, zapOutPool.amountOutMinA, routesA); } if (tokenB != _tokenOut) { balance = IERC20(tokenB).balanceOf(address(this)); if (routesB[routesB.length - 1].to != _tokenOut) revert InvalidRouteB(); _internalSwap(tokenB, balance, zapOutPool.amountOutMinB, routesB); } _returnAssets(tokenOut); } /// @dev Handles liquidity removing component of zap out. function _zapOutLiquidity(uint256 liquidity, Zap calldata zapOutPool) internal { address tokenA = zapOutPool.tokenA; address tokenB = zapOutPool.tokenB; address pool = poolFor(tokenA, tokenB, zapOutPool.stable, zapOutPool.factory); IERC20(pool).safeTransferFrom(msg.sender, pool, liquidity); (address token0, ) = sortTokens(tokenA, tokenB); (uint256 amount0, uint256 amount1) = IPool(pool).burn(address(this)); (uint256 amountA, uint256 amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); if (amountA < zapOutPool.amountAMin) revert InsufficientAmountA(); if (amountB < zapOutPool.amountBMin) revert InsufficientAmountB(); } /// @inheritdoc IRouter function generateZapInParams( address tokenA, address tokenB, bool stable, address _factory, uint256 amountInA, uint256 amountInB, Route[] calldata routesA, Route[] calldata routesB ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin) { amountOutMinA = amountInA; amountOutMinB = amountInB; uint256[] memory amounts; if (routesA.length > 0) { amounts = getAmountsOut(amountInA, routesA); amountOutMinA = amounts[amounts.length - 1]; } if (routesB.length > 0) { amounts = getAmountsOut(amountInB, routesB); amountOutMinB = amounts[amounts.length - 1]; } (amountAMin, amountBMin, ) = quoteAddLiquidity(tokenA, tokenB, stable, _factory, amountOutMinA, amountOutMinB); } /// @inheritdoc IRouter function generateZapOutParams( address tokenA, address tokenB, bool stable, address _factory, uint256 liquidity, Route[] calldata routesA, Route[] calldata routesB ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin) { (amountAMin, amountBMin) = quoteRemoveLiquidity(tokenA, tokenB, stable, _factory, liquidity); amountOutMinA = amountAMin; amountOutMinB = amountBMin; uint256[] memory amounts; if (routesA.length > 0) { amounts = getAmountsOut(amountAMin, routesA); amountOutMinA = amounts[amounts.length - 1]; } if (routesB.length > 0) { amounts = getAmountsOut(amountBMin, routesB); amountOutMinB = amounts[amounts.length - 1]; } } /// @dev Return residual assets from zapping. /// @param token token to return, put `ETHER` if you want Ether back. function _returnAssets(address token) internal { address sender = _msgSender(); uint256 balance; if (token == ETHER) { balance = IERC20(weth).balanceOf(address(this)); if (balance > 0) { IWETH(weth).withdraw(balance); _safeTransferETH(sender, balance); } } else { balance = IERC20(token).balanceOf(address(this)); if (balance > 0) { IERC20(token).safeTransfer(sender, balance); } } } /// @inheritdoc IRouter function quoteStableLiquidityRatio( address tokenA, address tokenB, address _factory ) external view returns (uint256 ratio) { IPool pool = IPool(poolFor(tokenA, tokenB, true, _factory)); uint256 decimalsA = 10 ** IERC20Metadata(tokenA).decimals(); uint256 decimalsB = 10 ** IERC20Metadata(tokenB).decimals(); uint256 investment = decimalsA; uint256 out = pool.getAmountOut(investment, tokenA); (uint256 amountA, uint256 amountB, ) = quoteAddLiquidity(tokenA, tokenB, true, _factory, investment, out); amountA = (amountA * 1e18) / decimalsA; amountB = (amountB * 1e18) / decimalsB; out = (out * 1e18) / decimalsB; investment = (investment * 1e18) / decimalsA; ratio = (((out * 1e18) / investment) * amountA) / amountB; return (investment * 1e18) / (ratio + 1e18); } function _safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); if (!success) revert ETHTransferFailed(); } function _safeTransfer(address token, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } function _safeTransferFrom(address token, address from, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value) ); require(success && (data.length == 0 || abi.decode(data, (bool)))); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IPool { error DepositsNotEqual(); error BelowMinimumK(); error FactoryAlreadySet(); error InsufficientLiquidity(); error InsufficientLiquidityMinted(); error InsufficientLiquidityBurned(); error InsufficientOutputAmount(); error InsufficientInputAmount(); error IsPaused(); error InvalidTo(); error K(); error NotEmergencyCouncil(); event Fees(address indexed sender, uint256 amount0, uint256 amount1); event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, address indexed to, uint256 amount0, uint256 amount1); event Swap( address indexed sender, address indexed to, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out ); event Sync(uint256 reserve0, uint256 reserve1); event Claim(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1); function metadata() external view returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1); function claimFees() external returns (uint256, uint256); function tokens() external view returns (address, address); function token0() external view returns (address); function token1() external view returns (address); function stable() external view returns (bool); function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external; function burn(address to) external returns (uint256 amount0, uint256 amount1); function mint(address to) external returns (uint256 liquidity); function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast); function getAmountOut(uint256, address) external view returns (uint256); function skim(address to) external; function initialize(address _token0, address _token1, bool _stable) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IPoolFactory { event SetFeeManager(address feeManager); event SetPauser(address pauser); event SetPauseState(bool state); event SetVoter(address voter); event PoolCreated(address indexed token0, address indexed token1, bool indexed stable, address pool, uint256); event SetCustomFee(address indexed pool, uint256 fee); error FeeInvalid(); error FeeTooHigh(); error InvalidPool(); error NotFeeManager(); error NotPauser(); error NotSinkConverter(); error NotVoter(); error PoolAlreadyExists(); error SameAddress(); error ZeroFee(); error ZeroAddress(); /// @notice returns the number of pools created from this factory function allPoolsLength() external view returns (uint256); /// @notice Is a valid pool created by this factory. /// @param . function isPool(address pool) external view returns (bool); /// @notice Support for Velodrome v1 which wraps around isPool(pool); /// @param . function isPair(address pool) external view returns (bool); /// @notice Return address of pool created by this factory /// @param tokenA . /// @param tokenB . /// @param stable True if stable, false if volatile function getPool(address tokenA, address tokenB, bool stable) external view returns (address); /// @notice Support for v3-style pools which wraps around getPool(tokenA,tokenB,stable) /// @dev fee is converted to stable boolean. /// @param tokenA . /// @param tokenB . /// @param fee 1 if stable, 0 if volatile, else returns address(0) function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address); /// @notice Support for Velodrome v1 pools as a "pool" was previously referenced as "pair" /// @notice Wraps around getPool(tokenA,tokenB,stable) function getPair(address tokenA, address tokenB, bool stable) external view returns (address); /// @dev Only called once to set to Voter.sol - Voter does not have a function /// to call this contract method, so once set it's immutable. /// This also follows convention of setVoterAndDistributor() in VotingEscrow.sol /// @param _voter . function setVoter(address _voter) external; function setSinkConverter(address _sinkConvert, address _velo, address _veloV2) external; function setPauser(address _pauser) external; function setPauseState(bool _state) external; function setFeeManager(address _feeManager) external; /// @notice Set default fee for stable and volatile pools. /// @dev Throws if higher than maximum fee. /// Throws if fee is zero. /// @param _stable Stable or volatile pool. /// @param _fee . function setFee(bool _stable, uint256 _fee) external; /// @notice Set overriding fee for a pool from the default /// @dev A custom fee of zero means the default fee will be used. function setCustomFee(address _pool, uint256 _fee) external; /// @notice Returns fee for a pool, as custom fees are possible. function getFee(address _pool, bool _stable) external view returns (uint256); /// @notice Create a pool given two tokens and if they're stable/volatile /// @dev token order does not matter /// @param tokenA . /// @param tokenB . /// @param stable . function createPool(address tokenA, address tokenB, bool stable) external returns (address pool); /// @notice Support for v3-style pools which wraps around createPool(tokena,tokenB,stable) /// @dev fee is converted to stable boolean /// @dev token order does not matter /// @param tokenA . /// @param tokenB . /// @param fee 1 if stable, 0 if volatile, else revert function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool); /// @notice Support for Velodrome v1 which wraps around createPool(tokenA,tokenB,stable) function createPair(address tokenA, address tokenB, bool stable) external returns (address pool); function isPaused() external view returns (bool); function velo() external view returns (address); function veloV2() external view returns (address); function voter() external view returns (address); function sinkConverter() external view returns (address); function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IPairFactoryV1 { function pairCodeHash() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IRouter { struct Route { address from; address to; bool stable; address factory; } error ConversionFromV2ToV1VeloProhibited(); error ETHTransferFailed(); error Expired(); error InsufficientAmount(); error InsufficientAmountA(); error InsufficientAmountB(); error InsufficientAmountADesired(); error InsufficientAmountBDesired(); error InsufficientAmountAOptimal(); error InsufficientLiquidity(); error InsufficientOutputAmount(); error InvalidAmountInForETHDeposit(); error InvalidTokenInForETHDeposit(); error InvalidPath(); error InvalidRouteA(); error InvalidRouteB(); error OnlyWETH(); error PoolDoesNotExist(); error PoolFactoryDoesNotExist(); error SameAddresses(); error ZeroAddress(); /// @dev Struct containing information necessary to zap in and out of pools /// @param tokenA . /// @param tokenB . /// @param stable Stable or volatile pool /// @param factory factory of pool /// @param amountOutMinA Minimum amount expected from swap leg of zap via routesA /// @param amountOutMinB Minimum amount expected from swap leg of zap via routesB /// @param amountAMin Minimum amount of tokenA expected from liquidity leg of zap /// @param amountBMin Minimum amount of tokenB expected from liquidity leg of zap struct Zap { address tokenA; address tokenB; bool stable; address factory; uint256 amountOutMinA; uint256 amountOutMinB; uint256 amountAMin; uint256 amountBMin; } /// @notice Sort two tokens by which address value is less than the other /// @param tokenA Address of token to sort /// @param tokenB Address of token to sort /// @return token0 Lower address value between tokenA and tokenB /// @return token1 Higher address value between tokenA and tokenB function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1); /// @notice Calculate the address of a pool by its' factory. /// Used by all Router functions containing a `Route[]` or `_factory` argument. /// Reverts if _factory is not approved by the FactoryRegistry /// @dev Returns a randomly generated address for a nonexistent pool /// @param tokenA Address of token to query /// @param tokenB Address of token to query /// @param stable True if pool is stable, false if volatile /// @param _factory Address of factory which created the pool function poolFor( address tokenA, address tokenB, bool stable, address _factory ) external view returns (address pool); /// @notice Wraps around poolFor(tokenA,tokenB,stable,_factory) for backwards compatibility to Velodrome v1 function pairFor( address tokenA, address tokenB, bool stable, address _factory ) external view returns (address pool); /// @notice Fetch and sort the reserves for a pool /// @param tokenA . /// @param tokenB . /// @param stable True if pool is stable, false if volatile /// @param _factory Address of PoolFactory for tokenA and tokenB /// @return reserveA Amount of reserves of the sorted token A /// @return reserveB Amount of reserves of the sorted token B function getReserves( address tokenA, address tokenB, bool stable, address _factory ) external view returns (uint256 reserveA, uint256 reserveB); /// @notice Perform chained getAmountOut calculations on any number of pools function getAmountsOut(uint256 amountIn, Route[] memory routes) external view returns (uint256[] memory amounts); // **** ADD LIQUIDITY **** /// @notice Quote the amount deposited into a Pool /// @param tokenA . /// @param tokenB . /// @param stable True if pool is stable, false if volatile /// @param _factory Address of PoolFactory for tokenA and tokenB /// @param amountADesired Amount of tokenA desired to deposit /// @param amountBDesired Amount of tokenB desired to deposit /// @return amountA Amount of tokenA to actually deposit /// @return amountB Amount of tokenB to actually deposit /// @return liquidity Amount of liquidity token returned from deposit function quoteAddLiquidity( address tokenA, address tokenB, bool stable, address _factory, uint256 amountADesired, uint256 amountBDesired ) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity); /// @notice Quote the amount of liquidity removed from a Pool /// @param tokenA . /// @param tokenB . /// @param stable True if pool is stable, false if volatile /// @param _factory Address of PoolFactory for tokenA and tokenB /// @param liquidity Amount of liquidity to remove /// @return amountA Amount of tokenA received /// @return amountB Amount of tokenB received function quoteRemoveLiquidity( address tokenA, address tokenB, bool stable, address _factory, uint256 liquidity ) external view returns (uint256 amountA, uint256 amountB); /// @notice Add liquidity of two tokens to a Pool /// @param tokenA . /// @param tokenB . /// @param stable True if pool is stable, false if volatile /// @param amountADesired Amount of tokenA desired to deposit /// @param amountBDesired Amount of tokenB desired to deposit /// @param amountAMin Minimum amount of tokenA to deposit /// @param amountBMin Minimum amount of tokenB to deposit /// @param to Recipient of liquidity token /// @param deadline Deadline to receive liquidity /// @return amountA Amount of tokenA to actually deposit /// @return amountB Amount of tokenB to actually deposit /// @return liquidity Amount of liquidity token returned from deposit function addLiquidity( address tokenA, address tokenB, bool stable, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); /// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool /// @param token . /// @param stable True if pool is stable, false if volatile /// @param amountTokenDesired Amount of token desired to deposit /// @param amountTokenMin Minimum amount of token to deposit /// @param amountETHMin Minimum amount of ETH to deposit /// @param to Recipient of liquidity token /// @param deadline Deadline to add liquidity /// @return amountToken Amount of token to actually deposit /// @return amountETH Amount of tokenETH to actually deposit /// @return liquidity Amount of liquidity token returned from deposit function addLiquidityETH( address token, bool stable, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity); // **** REMOVE LIQUIDITY **** /// @notice Remove liquidity of two tokens from a Pool /// @param tokenA . /// @param tokenB . /// @param stable True if pool is stable, false if volatile /// @param liquidity Amount of liquidity to remove /// @param amountAMin Minimum amount of tokenA to receive /// @param amountBMin Minimum amount of tokenB to receive /// @param to Recipient of tokens received /// @param deadline Deadline to remove liquidity /// @return amountA Amount of tokenA received /// @return amountB Amount of tokenB received function removeLiquidity( address tokenA, address tokenB, bool stable, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); /// @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool /// @param token . /// @param stable True if pool is stable, false if volatile /// @param liquidity Amount of liquidity to remove /// @param amountTokenMin Minimum amount of token to receive /// @param amountETHMin Minimum amount of ETH to receive /// @param to Recipient of liquidity token /// @param deadline Deadline to receive liquidity /// @return amountToken Amount of token received /// @return amountETH Amount of ETH received function removeLiquidityETH( address token, bool stable, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); /// @notice Remove liquidity of a fee-on-transfer token and WETH (returned as ETH) from a Pool /// @param token . /// @param stable True if pool is stable, false if volatile /// @param liquidity Amount of liquidity to remove /// @param amountTokenMin Minimum amount of token to receive /// @param amountETHMin Minimum amount of ETH to receive /// @param to Recipient of liquidity token /// @param deadline Deadline to receive liquidity /// @return amountETH Amount of ETH received function removeLiquidityETHSupportingFeeOnTransferTokens( address token, bool stable, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountETH); // **** SWAP **** /// @notice Swap one token for another /// @param amountIn Amount of token in /// @param amountOutMin Minimum amount of desired token received /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens /// @return amounts Array of amounts returned per route function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external returns (uint256[] memory amounts); /// @notice Swap ETH for a token /// @param amountOutMin Minimum amount of desired token received /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens /// @return amounts Array of amounts returned per route function swapExactETHForTokens( uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); /// @notice Swap a token for WETH (returned as ETH) /// @param amountIn Amount of token in /// @param amountOutMin Minimum amount of desired ETH /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens /// @return amounts Array of amounts returned per route function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external returns (uint256[] memory amounts); /// @notice Swap one token for another without slippage protection /// @return amounts Array of amounts to swap per route /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens function UNSAFE_swapExactTokensForTokens( uint256[] memory amounts, Route[] calldata routes, address to, uint256 deadline ) external returns (uint256[] memory); // **** SWAP (supporting fee-on-transfer tokens) **** /// @notice Swap one token for another supporting fee-on-transfer tokens /// @param amountIn Amount of token in /// @param amountOutMin Minimum amount of desired token received /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external; /// @notice Swap ETH for a token supporting fee-on-transfer tokens /// @param amountOutMin Minimum amount of desired token received /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external payable; /// @notice Swap a token for WETH (returned as ETH) supporting fee-on-transfer tokens /// @param amountIn Amount of token in /// @param amountOutMin Minimum amount of desired ETH /// @param routes Array of trade routes used in the swap /// @param to Recipient of the tokens received /// @param deadline Deadline to receive tokens function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, Route[] calldata routes, address to, uint256 deadline ) external; /// @notice Zap a token A into a pool (B, C). (A can be equal to B or C). /// Supports standard ERC20 tokens only (i.e. not fee-on-transfer tokens etc). /// Slippage is required for the initial swap. /// Additional slippage may be required when adding liquidity as the /// price of the token may have changed. /// @param tokenIn Token you are zapping in from (i.e. input token). /// @param amountInA Amount of input token you wish to send down routesA /// @param amountInB Amount of input token you wish to send down routesB /// @param zapInPool Contains zap struct information. See Zap struct. /// @param routesA Route used to convert input token to tokenA /// @param routesB Route used to convert input token to tokenB /// @param to Address you wish to mint liquidity to. /// @param stake Auto-stake liquidity in corresponding gauge. /// @return liquidity Amount of LP tokens created from zapping in. function zapIn( address tokenIn, uint256 amountInA, uint256 amountInB, Zap calldata zapInPool, Route[] calldata routesA, Route[] calldata routesB, address to, bool stake ) external payable returns (uint256 liquidity); /// @notice Zap out a pool (B, C) into A. /// Supports standard ERC20 tokens only (i.e. not fee-on-transfer tokens etc). /// Slippage is required for the removal of liquidity. /// Additional slippage may be required on the swap as the /// price of the token may have changed. /// @param tokenOut Token you are zapping out to (i.e. output token). /// @param liquidity Amount of liquidity you wish to remove. /// @param zapOutPool Contains zap struct information. See Zap struct. /// @param routesA Route used to convert tokenA into output token. /// @param routesB Route used to convert tokenB into output token. function zapOut( address tokenOut, uint256 liquidity, Zap calldata zapOutPool, Route[] calldata routesA, Route[] calldata routesB ) external; /// @notice Used to generate params required for zapping in. /// Zap in => remove liquidity then swap. /// Apply slippage to expected swap values to account for changes in reserves in between. /// @dev Output token refers to the token you want to zap in from. /// @param tokenA . /// @param tokenB . /// @param stable . /// @param _factory . /// @param amountInA Amount of input token you wish to send down routesA /// @param amountInB Amount of input token you wish to send down routesB /// @param routesA Route used to convert input token to tokenA /// @param routesB Route used to convert input token to tokenB /// @return amountOutMinA Minimum output expected from swapping input token to tokenA. /// @return amountOutMinB Minimum output expected from swapping input token to tokenB. /// @return amountAMin Minimum amount of tokenA expected from depositing liquidity. /// @return amountBMin Minimum amount of tokenB expected from depositing liquidity. function generateZapInParams( address tokenA, address tokenB, bool stable, address _factory, uint256 amountInA, uint256 amountInB, Route[] calldata routesA, Route[] calldata routesB ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin); /// @notice Used to generate params required for zapping out. /// Zap out => swap then add liquidity. /// Apply slippage to expected liquidity values to account for changes in reserves in between. /// @dev Output token refers to the token you want to zap out of. /// @param tokenA . /// @param tokenB . /// @param stable . /// @param _factory . /// @param liquidity Amount of liquidity being zapped out of into a given output token. /// @param routesA Route used to convert tokenA into output token. /// @param routesB Route used to convert tokenB into output token. /// @return amountOutMinA Minimum output expected from swapping tokenA into output token. /// @return amountOutMinB Minimum output expected from swapping tokenB into output token. /// @return amountAMin Minimum amount of tokenA expected from withdrawing liquidity. /// @return amountBMin Minimum amount of tokenB expected from withdrawing liquidity. function generateZapOutParams( address tokenA, address tokenB, bool stable, address _factory, uint256 liquidity, Route[] calldata routesA, Route[] calldata routesB ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin); /// @notice Used by zapper to determine appropriate ratio of A to B to deposit liquidity. Assumes stable pool. /// @dev Returns stable liquidity ratio of B to (A + B). /// E.g. if ratio is 0.4, it means there is more of A than there is of B. /// Therefore you should deposit more of token A than B. /// @param tokenA tokenA of stable pool you are zapping into. /// @param tokenB tokenB of stable pool you are zapping into. /// @param factory Factory that created stable pool. /// @return ratio Ratio of token0 to token1 required to deposit into zap. function quoteStableLiquidityRatio( address tokenA, address tokenB, address factory ) external view returns (uint256 ratio); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVoter { error AlreadyVotedOrDeposited(); error DistributeWindow(); error FactoryPathNotApproved(); error GaugeAlreadyKilled(); error GaugeAlreadyRevived(); error GaugeExists(); error GaugeDoesNotExist(address _pool); error GaugeNotAlive(address _gauge); error InactiveManagedNFT(); error MaximumVotingNumberTooLow(); error NonZeroVotes(); error NotAPool(); error NotApprovedOrOwner(); error NotGovernor(); error NotEmergencyCouncil(); error NotMinter(); error NotWhitelistedNFT(); error NotWhitelistedToken(); error SameValue(); error SpecialVotingWindow(); error TooManyPools(); error UnequalLengths(); error ZeroBalance(); error ZeroAddress(); event GaugeCreated( address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory, address pool, address bribeVotingReward, address feeVotingReward, address gauge, address creator ); event GaugeKilled(address indexed gauge); event GaugeRevived(address indexed gauge); event Voted( address indexed voter, address indexed pool, uint256 indexed tokenId, uint256 weight, uint256 totalWeight, uint256 timestamp ); event Abstained( address indexed voter, address indexed pool, uint256 indexed tokenId, uint256 weight, uint256 totalWeight, uint256 timestamp ); event NotifyReward(address indexed sender, address indexed reward, uint256 amount); event DistributeReward(address indexed sender, address indexed gauge, uint256 amount); event WhitelistToken(address indexed whitelister, address indexed token, bool indexed _bool); event WhitelistNFT(address indexed whitelister, uint256 indexed tokenId, bool indexed _bool); // mappings function gauges(address pool) external view returns (address); function poolForGauge(address gauge) external view returns (address); function gaugeToFees(address gauge) external view returns (address); function gaugeToBribe(address gauge) external view returns (address); function weights(address pool) external view returns (uint256); function votes(uint256 tokenId, address pool) external view returns (uint256); function usedWeights(uint256 tokenId) external view returns (uint256); function lastVoted(uint256 tokenId) external view returns (uint256); function isGauge(address) external view returns (bool); function isWhitelistedToken(address token) external view returns (bool); function isWhitelistedNFT(uint256 tokenId) external view returns (bool); function isAlive(address gauge) external view returns (bool); function ve() external view returns (address); function governor() external view returns (address); function epochGovernor() external view returns (address); function emergencyCouncil() external view returns (address); function length() external view returns (uint256); /// @notice Called by Minter to distribute weekly emissions rewards for disbursement amongst gauges. /// @dev Assumes totalWeight != 0 (Will never be zero as long as users are voting). /// Throws if not called by minter. /// @param _amount Amount of rewards to distribute. function notifyRewardAmount(uint256 _amount) external; /// @dev Utility to distribute to gauges of pools in range _start to _finish. /// @param _start Starting index of gauges to distribute to. /// @param _finish Ending index of gauges to distribute to. function distribute(uint256 _start, uint256 _finish) external; /// @dev Utility to distribute to gauges of pools in array. /// @param _gauges Array of gauges to distribute to. function distribute(address[] memory _gauges) external; /// @notice Called by users to update voting balances in voting rewards contracts. /// @param _tokenId Id of veNFT whose balance you wish to update. function poke(uint256 _tokenId) external; /// @notice Called by users to vote for pools. Votes distributed proportionally based on weights. /// Can only vote or deposit into a managed NFT once per epoch. /// Can only vote for gauges that have not been killed. /// @dev Weights are distributed proportional to the sum of the weights in the array. /// Throws if length of _poolVote and _weights do not match. /// @param _tokenId Id of veNFT you are voting with. /// @param _poolVote Array of pools you are voting for. /// @param _weights Weights of pools. function vote(uint256 _tokenId, address[] calldata _poolVote, uint256[] calldata _weights) external; /// @notice Called by users to reset voting state. Required if you wish to make changes to /// veNFT state (e.g. merge, split, deposit into managed etc). /// Cannot reset in the same epoch that you voted in. /// Can vote or deposit into a managed NFT again after reset. /// @param _tokenId Id of veNFT you are reseting. function reset(uint256 _tokenId) external; /// @notice Called by users to deposit into a managed NFT. /// Can only vote or deposit into a managed NFT once per epoch. /// Note that NFTs deposited into a managed NFT will be re-locked /// to the maximum lock time on withdrawal. /// @dev Throws if not approved or owner. /// Throws if managed NFT is inactive. /// Throws if depositing within privileged window (one hour prior to epoch flip). function depositManaged(uint256 _tokenId, uint256 _mTokenId) external; /// @notice Called by users to withdraw from a managed NFT. /// Cannot do it in the same epoch that you deposited into a managed NFT. /// Can vote or deposit into a managed NFT again after withdrawing. /// Note that the NFT withdrawn is re-locked to the maximum lock time. function withdrawManaged(uint256 _tokenId) external; /// @notice Claim emissions from gauges. /// @param _gauges Array of gauges to collect emissions from. function claimRewards(address[] memory _gauges) external; /// @notice Claim bribes for a given NFT. /// @dev Utility to help batch bribe claims. /// @param _bribes Array of BribeVotingReward contracts to collect from. /// @param _tokens Array of tokens that are used as bribes. /// @param _tokenId Id of veNFT that you wish to claim bribes for. function claimBribes(address[] memory _bribes, address[][] memory _tokens, uint256 _tokenId) external; /// @notice Claim fees for a given NFT. /// @dev Utility to help batch fee claims. /// @param _fees Array of FeesVotingReward contracts to collect from. /// @param _tokens Array of tokens that are used as fees. /// @param _tokenId Id of veNFT that you wish to claim fees for. function claimFees(address[] memory _fees, address[][] memory _tokens, uint256 _tokenId) external; /// @notice Set new governor. /// @dev Throws if not called by governor. /// @param _governor . function setGovernor(address _governor) external; /// @notice Set new epoch based governor. /// @dev Throws if not called by governor. /// @param _epochGovernor . function setEpochGovernor(address _epochGovernor) external; /// @notice Set new emergency council. /// @dev Throws if not called by emergency council. /// @param _emergencyCouncil . function setEmergencyCouncil(address _emergencyCouncil) external; /// @notice Whitelist (or unwhitelist) token for use in bribes. /// @dev Throws if not called by governor. /// @param _token . /// @param _bool . function whitelistToken(address _token, bool _bool) external; /// @notice Whitelist (or unwhitelist) token id for voting in last hour prior to epoch flip. /// @dev Throws if not called by governor. /// Throws if already whitelisted. /// @param _tokenId . /// @param _bool . function whitelistNFT(uint256 _tokenId, bool _bool) external; /// @notice Create a new gauge (unpermissioned). /// @dev Governor can create a new gauge for a pool with any address. /// @dev V1 gauges can only be created by governor. /// @param _poolFactory . /// @param _pool . function createGauge(address _poolFactory, address _pool) external returns (address); /// @notice Kills a gauge. The gauge will not receive any new emissions and cannot be deposited into. /// Can still withdraw from gauge. /// @dev Throws if not called by emergency council. /// Throws if gauge already killed. /// @param _gauge . function killGauge(address _gauge) external; /// @notice Revives a killed gauge. Gauge will can receive emissions and deposits again. /// @dev Throws if not called by emergency council. /// Throws if gauge is not killed. /// @param _gauge . function reviveGauge(address _gauge) external; /// @dev Update claims to emissions for an array of gauges. /// @param _gauges Array of gauges to update emissions for. function updateFor(address[] memory _gauges) external; /// @dev Update claims to emissions for gauges based on their pool id as stored in Voter. /// @param _start Starting index of pools. /// @param _end Ending index of pools. function updateFor(uint256 _start, uint256 _end) external; /// @dev Update claims to emissions for single gauge /// @param _gauge . function updateFor(address _gauge) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IGauge { error NotAlive(); error NotAuthorized(); error NotVoter(); error RewardRateTooHigh(); error ZeroAmount(); error ZeroRewardRate(); event Deposit(address indexed from, address indexed to, uint256 amount); event Withdraw(address indexed from, uint256 amount); event NotifyReward(address indexed from, uint256 amount); event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1); event ClaimRewards(address indexed from, uint256 amount); function rewardPerToken() external view returns (uint256 _rewardPerToken); /// @notice Returns the last time the reward was modified or periodFinish if the reward has ended function lastTimeRewardApplicable() external view returns (uint256 _time); /// @notice Returns accrued balance to date from last claim / first deposit. function earned(address _account) external view returns (uint256 _earned); function left() external view returns (uint256 _left); /// @notice Returns if gauge is linked to a legitimate Velodrome pool function isPool() external view returns (bool _isPool); function stakingToken() external view returns (address _pool); /// @notice Retrieve rewards for an address. /// @dev Throws if not called by same address or voter. /// @param _account . function getReward(address _account) external; /// @notice Deposit LP tokens into gauge for msg.sender /// @param _amount . function deposit(uint256 _amount) external; /// @notice Deposit LP tokens into gauge for any user /// @param _amount . /// @param _recipient Recipient to give balance to function deposit(uint256 _amount, address _recipient) external; /// @notice Withdraw LP tokens for user /// @param _amount . function withdraw(uint256 _amount) external; /// @dev Notifies gauge of gauge rewards. Assumes gauge reward tokens is 18 decimals. /// If not 18 decimals, rewardRate may have rounding issues. function notifyRewardAmount(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFactoryRegistry { error FallbackFactory(); error InvalidFactoriesToPoolFactory(); error PathAlreadyApproved(); error PathNotApproved(); error SameAddress(); error ZeroAddress(); event Approve(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory); event Unapprove(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory); event SetManagedRewardsFactory(address indexed _newRewardsFactory); /// @notice Approve a set of factories used in Velodrome Protocol. /// Router.sol is able to swap any poolFactories currently approved. /// Cannot approve address(0) factories. /// Cannot aprove path that is already approved. /// Each poolFactory has one unique set and maintains state. In the case a poolFactory is unapproved /// and then re-approved, the same set of factories must be used. In other words, you cannot overwrite /// the factories tied to a poolFactory address. /// VotingRewardsFactories and GaugeFactories may use the same address across multiple poolFactories. /// @dev Callable by onlyOwner /// @param poolFactory . /// @param votingRewardsFactory . /// @param gaugeFactory . function approve(address poolFactory, address votingRewardsFactory, address gaugeFactory) external; /// @notice Unapprove a set of factories used in Velodrome Protocol. /// While a poolFactory is unapproved, Router.sol cannot swap with pools made from the corresponding factory /// Can only unapprove an approved path. /// Cannot unapprove the fallback path (core v2 factories). /// @dev Callable by onlyOwner /// @param poolFactory . function unapprove(address poolFactory) external; /// @notice Factory to create free and locked rewards for a managed veNFT function managedRewardsFactory() external view returns (address); /// @notice Set the rewards factory address /// @dev Callable by onlyOwner /// @param _newManagedRewardsFactory address of new managedRewardsFactory function setManagedRewardsFactory(address _newManagedRewardsFactory) external; /// @notice Get the factories correlated to a poolFactory. /// Once set, this can never be modified. /// Returns the correlated factories even after an approved poolFactory is unapproved. function factoriesToPoolFactory( address poolFactory ) external view returns (address votingRewardsFactory, address gaugeFactory); /// @notice Get all PoolFactories approved by the registry /// @dev The same PoolFactory address cannot be used twice /// @return Array of PoolFactory addresses function poolFactories() external view returns (address[] memory); /// @notice Check if a PoolFactory is approved within the factory registry. Router uses this method to /// ensure a pool swapped from is approved. /// @param poolFactory . /// @return True if PoolFactory is approved, else false function isPoolFactoryApproved(address poolFactory) external view returns (bool); /// @notice Get the length of the poolFactories array function poolFactoriesLength() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol) pragma solidity ^0.8.9; import "../utils/Context.sol"; /** * @dev Context variant with ERC2771 support. */ abstract contract ERC2771Context is Context { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _trustedForwarder; /// @custom:oz-upgrades-unsafe-allow constructor constructor(address trustedForwarder) { _trustedForwarder = trustedForwarder; } function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == _trustedForwarder; } function _msgSender() internal view virtual override returns (address sender) { if (isTrustedForwarder(msg.sender)) { // The assembly code is more direct than the Solidity version using `abi.decode`. /// @solidity memory-safe-assembly assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return super._msgSender(); } } function _msgData() internal view virtual override returns (bytes calldata) { if (isTrustedForwarder(msg.sender)) { return msg.data[:msg.data.length - 20]; } else { return super._msgData(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "remappings": [ "@opengsn/=lib/gsn/packages/", "@openzeppelin/=lib/openzeppelin-contracts/", "@uniswap/v3-core/=lib/v3-core/", "concentrated-liquidity/=lib/concentrated-liquidity/", "ds-test/=lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "forge-std/=lib/forge-std/src/", "gsn/=lib/gsn/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "utils/=test/utils/", "v3-core/=lib/v3-core/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "contracts/art/PerlinNoise.sol": { "PerlinNoise": "0x08947e304064b3f3ef2b99fca7e549c5fc3f75d4" }, "contracts/art/Trig.sol": { "Trig": "0xbdd6f9662e904a9176aafcbdded45d076b5170ef" }, "contracts/libraries/BalanceLogicLibrary.sol": { "BalanceLogicLibrary": "0x79bca9bcc19e157cb5f8c5a2f4d6cb951b1f8dce" }, "contracts/libraries/DelegationLogicLibrary.sol": { "DelegationLogicLibrary": "0x73746410b0dd4526e1fa00d0854e99ba54aefd30" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"},{"internalType":"address","name":"_factoryRegistry","type":"address"},{"internalType":"address","name":"_v1Factory","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ConversionFromV2ToV1VeloProhibited","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InsufficientAmountA","type":"error"},{"inputs":[],"name":"InsufficientAmountADesired","type":"error"},{"inputs":[],"name":"InsufficientAmountAOptimal","type":"error"},{"inputs":[],"name":"InsufficientAmountB","type":"error"},{"inputs":[],"name":"InsufficientAmountBDesired","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidAmountInForETHDeposit","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"InvalidRouteA","type":"error"},{"inputs":[],"name":"InvalidRouteB","type":"error"},{"inputs":[],"name":"InvalidTokenInForETHDeposit","type":"error"},{"inputs":[],"name":"OnlyWETH","type":"error"},{"inputs":[],"name":"PoolDoesNotExist","type":"error"},{"inputs":[],"name":"PoolFactoryDoesNotExist","type":"error"},{"inputs":[],"name":"SameAddresses","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ETHER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"UNSAFE_swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"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":"bool","name":"stable","type":"bool"},{"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":"defaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"amountInA","type":"uint256"},{"internalType":"uint256","name":"amountInB","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"generateZapInParams","outputs":[{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"generateZapOutParams","outputs":[{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"}],"name":"getReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"}],"name":"pairFor","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"}],"name":"poolFor","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"}],"name":"quoteAddLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"quoteRemoveLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"address","name":"_factory","type":"address"}],"name":"quoteStableLiquidityRatio","outputs":[{"internalType":"uint256","name":"ratio","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"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":"bool","name":"stable","type":"bool"},{"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":"bool","name":"stable","type":"bool"},{"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":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"sortTokens","outputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"v1Factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountInA","type":"uint256"},{"internalType":"uint256","name":"amountInB","type":"uint256"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"internalType":"struct IRouter.Zap","name":"zapInPool","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stake","type":"bool"}],"name":"zapIn","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"internalType":"struct IRouter.Zap","name":"zapOutPool","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"zapOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101406040523480156200001257600080fd5b50604051620061f5380380620061f5833981016040819052620000359162000082565b6001600160a01b0395861660805293851660a05291841660c052831660e052821661010052166101205262000103565b80516001600160a01b03811681146200007d57600080fd5b919050565b60008060008060008060c087890312156200009c57600080fd5b620000a78762000065565b9550620000b76020880162000065565b9450620000c76040880162000065565b9350620000d76060880162000065565b9250620000e76080880162000065565b9150620000f760a0880162000065565b90509295509295509295565b60805160a05160c05160e0516101005161012051615f9f62000256600039600081816101ec0152818161033c015281816109dd01528181610bb301528181610c5f01528181610ce301528181610d6201528181610dd601528181611eb001528181611fc501528181612053015281816121d6015281816124b9015281816124ef01528181612545015281816125da0152818161270c015281816128de01528181612e0a01528181612e5a015281816131b8015281816131db01528181613542015281816135fb0152818161445a01526144eb0152600081816103c5015261337f01526000818161066b0152818161088701528181611351015281816115750152818161177d0152818161251101528181613fc10152818161406201526140ec0152600081816105110152611a330152600081816102dd01526117d6015260008181610464015261369d0152615f9f6000f3fe6080604052600436106101dc5760003560e01c8063874029d911610102578063cac88ea911610095578063e4ea9d7411610064578063e4ea9d74146106ad578063f5ba53c7146106cd578063fb49bafd146106fb578063fe411f141461070e57600080fd5b8063cac88ea914610619578063ce700c2914610639578063d4b6846d14610659578063d7b0e0a51461068d57600080fd5b8063a81b9159116100d1578063a81b9159146105a6578063b7e0d4c0146105c6578063c6b7f1b6146105d9578063c92de3ec146105f957600080fd5b8063874029d91461053357806388cd821e146105535780638c0037dc14610573578063903638a41461059357600080fd5b806342cb1fbc1161017a578063572b6c0511610149578063572b6c05146104475780635a47ddc3146104a45780637539d413146104df5780638083f7bb146104ff57600080fd5b806342cb1fbc1461038b57806346c96aac146103b3578063544caa56146103e75780635509a1ac1461042757600080fd5b80633bf0c9fb116101b65780633bf0c9fb146102cb5780633da5acba146103175780633fc8cef31461032a5780634111d5971461035e57600080fd5b806307db50fa146102315780630dede6c41461027657806312bc3aca146102ab57600080fd5b3661022c57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461022a576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561023d57600080fd5b5061025161024c3660046151a5565b61072e565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561028257600080fd5b50610296610291366004615275565b610870565b6040805192835260208301919091520161026d565b3480156102b757600080fd5b5061022a6102c63660046152fa565b6109c9565b3480156102d757600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161026d565b61022a61032536600461536c565b610cd7565b34801561033657600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561036a57600080fd5b5061037e61037936600461543b565b611068565b60405161026d9190615506565b34801561039757600080fd5b506102ff73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b3480156103bf57600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103f357600080fd5b5061040761040236600461554a565b6111c8565b604080516001600160a01b0393841681529290911660208301520161026d565b34801561043357600080fd5b5061037e61044236600461560b565b611253565b34801561045357600080fd5b506104946104623660046156b2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b604051901515815260200161026d565b3480156104b057600080fd5b506104c46104bf3660046156cf565b611548565b6040805193845260208401929092529082015260600161026d565b3480156104eb57600080fd5b506102516104fa36600461575e565b611640565b34801561050b57600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561053f57600080fd5b506102ff61054e366004615823565b611779565b34801561055f57600080fd5b5061022a61056e3660046152fa565b611c67565b34801561057f57600080fd5b5061029661058e366004615823565b611de8565b61037e6105a136600461536c565b611ea2565b3480156105b257600080fd5b5061022a6105c1366004615898565b612183565b6104c46105d4366004615938565b6124a4565b3480156105e557600080fd5b5061037e6105f43660046152fa565b6126f6565b34801561060557600080fd5b506102966106143660046159aa565b6129bd565b34801561062557600080fd5b5061037e6106343660046152fa565b612b06565b34801561064557600080fd5b506104c4610654366004615a0e565b612c15565b34801561066557600080fd5b506102ff7f000000000000000000000000000000000000000000000000000000000000000081565b34801561069957600080fd5b506102966106a8366004615938565b612df7565b3480156106b957600080fd5b506102ff6106c8366004615823565b612ed5565b3480156106d957600080fd5b506106ed6106e8366004615a7c565b612eec565b60405190815260200161026d565b6106ed610709366004615ac7565b613160565b34801561071a57600080fd5b506106ed610729366004615938565b613530565b8585600080606087156107c3576107978b8a8a808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761077e60808302860136819003810190615b98565b81526020019060010190610761565b5050505050611253565b905080600182516107a89190615bca565b815181106107b8576107b8615bdd565b602002602001015194505b85156108475761081b8a8888808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761080c60808302860136819003810190615b98565b815260200190600101906107ef565b9050806001825161082c9190615bca565b8151811061083c5761083c615bdd565b602002602001015193505b6108558f8f8f8f8989612c15565b508093508194505050509a509a509a509a9650505050505050565b6000808261087d81613675565b60006108ab8c8c8c7f0000000000000000000000000000000000000000000000000000000000000000611779565b90506108ca6108b8613699565b6001600160a01b03831690838c6136dd565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015610916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093a9190615bf3565b91509150600061094a8f8f6111c8565b509050806001600160a01b03168f6001600160a01b03161461096d578183610970565b82825b90975095508a871015610996576040516323d9bb0560e21b815260040160405180910390fd5b898610156109b757604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b806109d381613675565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168585610a0a600182615bca565b818110610a1957610a19615bdd565b9050608002016020016020810190610a3191906156b2565b6001600160a01b031614610a58576040516320db826760e01b815260040160405180910390fd5b610b3f85856000818110610a6e57610a6e615bdd565b610a8492602060809092020190810191506156b2565b610a8c613699565b610b3988886000818110610aa257610aa2615bdd565b610ab892602060809092020190810191506156b2565b89896000818110610acb57610acb615bdd565b9050608002016020016020810190610ae391906156b2565b8a8a6000818110610af657610af6615bdd565b9050608002016040016020810190610b0e9190615c17565b8b8b6000818110610b2157610b21615bdd565b905060800201606001602081019061054e91906156b2565b8a61374e565b610b9b8585808060200260200160405190810160405280939291908181526020016000905b82821015610b9057610b8160808302860136819003810190615b98565b81526020019060010190610b64565b505050505030613846565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c269190615c34565b905086811015610c49576040516342301c2360e01b815260040160405180910390fd5b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610cab57600080fd5b505af1158015610cbf573d6000803e3d6000fd5b50505050610ccd8482613c6f565b5050505050505050565b80610ce181613675565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685856000818110610d1e57610d1e615bdd565b610d3492602060809092020190810191506156b2565b6001600160a01b031614610d5b576040516320db826760e01b815260040160405180910390fd5b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb610e1988886000818110610aa257610aa2615bdd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610e66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8a9190615c4d565b610e9657610e96615c6a565b6000610ea3600187615bca565b90506000878783818110610eb957610eb9615bdd565b9050608002016020016020810190610ed191906156b2565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190615c34565b9050610f9b8888808060200260200160405190810160405280939291908181526020016000905b82821015610f9057610f8160808302860136819003810190615b98565b81526020019060010190610f64565b505050505087613846565b8881898985818110610faf57610faf615bdd565b9050608002016020016020810190610fc791906156b2565b6040516370a0823160e01b81526001600160a01b038a8116600483015291909116906370a08231906024015b602060405180830381865afa158015611010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110349190615c34565b61103e9190615bca565b101561105d576040516342301c2360e01b815260040160405180910390fd5b505050505050505050565b60608161107481613675565b61115d8686600081811061108a5761108a615bdd565b6110a092602060809092020190810191506156b2565b6110a8613699565b61113d898960008181106110be576110be615bdd565b6110d492602060809092020190810191506156b2565b8a8a60008181106110e7576110e7615bdd565b90506080020160200160208101906110ff91906156b2565b8b8b600081811061111257611112615bdd565b905060800201604001602081019061112a9190615c17565b8c8c6000818110610b2157610b21615bdd565b8a60008151811061115057611150615bdd565b602002602001015161374e565b6111ba878787808060200260200160405190810160405280939291908181526020016000905b828210156111af576111a060808302860136819003810190615b98565b81526020019060010190611183565b505050505086613d02565b8691505b5095945050505050565b600080826001600160a01b0316846001600160a01b0316036111fd57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b03161061121d578284611220565b83835b90925090506001600160a01b03821661124c5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b6060600182511015611278576040516320db826760e01b815260040160405180910390fd5b8151611285906001615c80565b6001600160401b0381111561129c5761129c6153d2565b6040519080825280602002602001820160405280156112c5578160200160208202803683370190505b50905082816000815181106112dc576112dc615bdd565b6020908102919091010152815160005b81811015611540576000806001600160a01b031685838151811061131257611312615bdd565b6020026020010151606001516001600160a01b03161461134f5784828151811061133e5761133e615bdd565b602002602001015160600151611371565b7f00000000000000000000000000000000000000000000000000000000000000005b905060006113d886848151811061138a5761138a615bdd565b6020026020010151600001518785815181106113a8576113a8615bdd565b6020026020010151602001518886815181106113c6576113c6615bdd565b60200260200101516040015185611779565b60405163e5e31b1360e01b81526001600160a01b0380831660048301529192509083169063e5e31b1390602401602060405180830381865afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114469190615c4d565b1561152b57806001600160a01b031663f140a35a86858151811061146c5761146c615bdd565b602002602001015188868151811061148657611486615bdd565b6020026020010151600001516040518363ffffffff1660e01b81526004016114c19291909182526001600160a01b0316602082015260400190565b602060405180830381865afa1580156114de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115029190615c34565b8561150e856001615c80565b8151811061151e5761151e615bdd565b6020026020010181815250505b5050808061153890615c93565b9150506112ec565b505092915050565b60008060008361155781613675565b6115668d8d8d8d8d8d8d613f62565b909450925060006115998e8e8e7f0000000000000000000000000000000000000000000000000000000000000000611779565b90506115ae8e6115a7613699565b838861374e565b6115c18d6115ba613699565b838761374e565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af1158015611609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162d9190615c34565b9250505099509950999650505050505050565b6000806000806116538d8d8d8d8d6129bd565b9094509250839150829050606087156116e4576116b8838a8a808060200260200160405190810160405280939291908181526020016000905b8282101561078d576116a960808302860136819003810190615b98565b8152602001906001019061168c565b905080600182516116c99190615bca565b815181106116d9576116d9615bdd565b602002602001015194505b85156117685761173c828888808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761172d60808302860136819003810190615b98565b81526020019060010190611710565b9050806001825161174d9190615bca565b8151811061175d5761175d615bdd565b602002602001015193505b509950995099509995505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000816001600160a01b038416156117b257836117b4565b815b60405163d1ea0a1d60e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063d1ea0a1d90602401602060405180830381865afa15801561181f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118439190615c4d565b61186057604051634d39d5a360e11b815260040160405180910390fd5b6000826001600160a01b0316638c7c53ce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c49190615cac565b90506000836001600160a01b031663c6751c096040518163ffffffff1660e01b8152600401602060405180830381865afa158015611906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192a9190615cac565b9050806001600160a01b0316896001600160a01b031614801561195e5750816001600160a01b0316886001600160a01b0316145b1561197c57604051639cda859960e01b815260040160405180910390fd5b816001600160a01b0316896001600160a01b03161480156119ae5750806001600160a01b0316886001600160a01b0316145b15611a2057836001600160a01b0316638e39ee166040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a159190615cac565b945050505050611c5f565b600080611a2d8b8b6111c8565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614611b6357600082828b604051602001611a8193929190615cc9565b604051602081830303815290604052805190602001209050611b5b866001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ada573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afe9190615cac565b604051603881018990526f5af43d82803e903d91602b57fd5bf3ff60248201526014810191909152733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018390526037600c8201206078820152605560439091012090565b975050611c58565b6000856001600160a01b0316639aab92486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc79190615c34565b90508583838c604051602001611bdf93929190615cc9565b6040516020818303038152906040528051906020012082604051602001611c3b939291906001600160f81b0319815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b6040516020818303038152906040528051906020012060001c9750505b5050505050505b949350505050565b80611c7181613675565b611c8785856000818110610a6e57610a6e615bdd565b6000611c94600186615bca565b90506000868683818110611caa57611caa615bdd565b9050608002016020016020810190611cc291906156b2565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a0823190602401602060405180830381865afa158015611d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2e9190615c34565b9050611d8c8787808060200260200160405190810160405280939291908181526020016000905b82821015611d8157611d7260808302860136819003810190615b98565b81526020019060010190611d55565b505050505086613846565b8781888885818110611da057611da0615bdd565b9050608002016020016020810190611db891906156b2565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401610ff3565b6000806000611df787876111c8565b509050600080611e0989898989611779565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a9190615cfc565b5091509150826001600160a01b0316896001600160a01b031614611e8f578082611e92565b81815b909a909950975050505050505050565b606081611eae81613675565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686866000818110611eeb57611eeb615bdd565b611f0192602060809092020190810191506156b2565b6001600160a01b031614611f28576040516320db826760e01b815260040160405180910390fd5b611f7a348787808060200260200160405190810160405280939291908181526020016000905b8282101561078d57611f6b60808302860136819003810190615b98565b81526020019060010190611f4e565b9150868260018451611f8c9190615bca565b81518110611f9c57611f9c615bdd565b60200260200101511015611fc3576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08360008151811061200557612005615bdd565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561203857600080fd5b505af115801561204c573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb61209688886000818110610aa257610aa2615bdd565b846000815181106120a9576120a9615bdd565b60200260200101516040518363ffffffff1660e01b81526004016120e29291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121259190615c4d565b61213157612131615c6a565b6111be828787808060200260200160405190810160405280939291908181526020016000905b828210156111af5761217460808302860136819003810190615b98565b81526020019060010190612157565b600061219260208701876156b2565b905060006121a660408801602089016156b2565b905060006001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146121d457896121f6565b7f00000000000000000000000000000000000000000000000000000000000000005b905061220289896141cb565b6000816001600160a01b0316846001600160a01b03161461234e576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122859190615c34565b90506001600160a01b038216888861229e600182615bca565b8181106122ad576122ad615bdd565b90506080020160200160208101906122c591906156b2565b6001600160a01b0316146122ec576040516309d41c6760e31b815260040160405180910390fd5b61234e84828b608001358b8b808060200260200160405190810160405280939291908181526020016000905b828210156123445761233560808302860136819003810190615b98565b81526020019060010190612318565b5050505050614330565b816001600160a01b0316836001600160a01b03161461248e576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156123ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cf9190615c34565b90506001600160a01b03821686866123e8600182615bca565b8181106123f7576123f7615bdd565b905060800201602001602081019061240f91906156b2565b6001600160a01b031614612436576040516332b2410360e21b815260040160405180910390fd5b61248e83828b60a001358989808060200260200160405190810160405280939291908181526020016000905b828210156123445761247f60808302860136819003810190615b98565b81526020019060010190612462565b6124978b614412565b5050505050505050505050565b6000806000836124b381613675565b6124e28b7f00000000000000000000000000000000000000000000000000000000000000008c8c348d8d613f62565b909450925060006125358c7f00000000000000000000000000000000000000000000000000000000000000008d7f0000000000000000000000000000000000000000000000000000000000000000611779565b90506125438c6115a7613699565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561259e57600080fd5b505af11580156125b2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015612627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264b9190615c4d565b61265757612657615c6a565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561269f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c39190615c34565b9250833411156126e7576126e76126d8613699565b6126e28634615bca565b613c6f565b50509750975097945050505050565b60608161270281613675565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168686612739600182615bca565b81811061274857612748615bdd565b905060800201602001602081019061276091906156b2565b6001600160a01b031614612787576040516320db826760e01b815260040160405180910390fd5b6127d9888787808060200260200160405190810160405280939291908181526020016000905b8282101561078d576127ca60808302860136819003810190615b98565b815260200190600101906127ad565b91508682600184516127eb9190615bca565b815181106127fb576127fb615bdd565b60200260200101511015612822576040516342301c2360e01b815260040160405180910390fd5b61287f8686600081811061283857612838615bdd565b61284e92602060809092020190810191506156b2565b612856613699565b61286c898960008181106110be576110be615bdd565b8560008151811061115057611150615bdd565b6128dc828787808060200260200160405190810160405280939291908181526020016000905b828210156128d1576128c260808302860136819003810190615b98565b815260200190600101906128a5565b505050505030613d02565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836001855161291a9190615bca565b8151811061292a5761292a615bdd565b60200260200101516040518263ffffffff1660e01b815260040161295091815260200190565b600060405180830381600087803b15801561296a57600080fd5b505af115801561297e573d6000803e3d6000fd5b505050506129b28483600185516129959190615bca565b815181106129a5576129a5615bdd565b6020026020010151613c6f565b509695505050505050565b6000806000846001600160a01b0316636801cc308989896040518463ffffffff1660e01b81526004016129f293929190615d2a565b602060405180830381865afa158015612a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a339190615cac565b90506001600160a01b038116612a50576000809250925050612afc565b600080612a5f8a8a8a8a611de8565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190615c34565b905080612ad48489615d4e565b612ade9190615d7b565b955080612aeb8389615d4e565b612af59190615d7b565b9450505050505b9550959350505050565b606081612b1281613675565b612b64888787808060200260200160405190810160405280939291908181526020016000905b8282101561078d57612b5560808302860136819003810190615b98565b81526020019060010190612b38565b9150868260018451612b769190615bca565b81518110612b8657612b86615bdd565b60200260200101511015612bad576040516342301c2360e01b815260040160405180910390fd5b612bc38686600081811061283857612838615bdd565b6129b2828787808060200260200160405190810160405280939291908181526020016000905b828210156111af57612c0660808302860136819003810190615b98565b81526020019060010190612be9565b600080600080866001600160a01b0316636801cc308b8b8b6040518463ffffffff1660e01b8152600401612c4b93929190615d2a565b602060405180830381865afa158015612c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8c9190615cac565b9050600080806001600160a01b03841615612d1757836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d039190615c34565b9050612d118d8d8d8d611de8565b90935091505b82158015612d23575081155b15612d54578896508795506103e8612d43612d3e888a615d4e565b6145dd565b612d4d9190615bca565b9450612de7565b6000612d618a85856146cc565b9050888111612da957899750955085612da284612d7e848b615d4e565b612d889190615d7b565b84612d93858b615d4e565b612d9d9190615d7b565b61472d565b9550612de5565b6000612db68a85876146cc565b9850899750889050612de185612dcc8584615d4e565b612dd69190615d7b565b85612d93868c615d4e565b9650505b505b5050505096509650969350505050565b60008082612e0481613675565b612e348a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b610870565b9093509150612e448a8685614747565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612ea657600080fd5b505af1158015612eba573d6000803e3d6000fd5b50505050612ec88583613c6f565b5097509795505050505050565b6000612ee385858585611779565b95945050505050565b600080612efc8585600186611779565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f629190615d9d565b612f6d90600a615ea4565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd39190615d9d565b612fde90600a615ea4565b6040516378a051ad60e11b8152600481018490526001600160a01b03898116602483015291925083916000919086169063f140a35a90604401602060405180830381865afa158015613034573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130589190615c34565b905060008061306c8b8b60018c8888612c15565b5090925090508561308583670de0b6b3a7640000615d4e565b61308f9190615d7b565b9150846130a482670de0b6b3a7640000615d4e565b6130ae9190615d7b565b9050846130c384670de0b6b3a7640000615d4e565b6130cd9190615d7b565b9250856130e285670de0b6b3a7640000615d4e565b6130ec9190615d7b565b935080828561310386670de0b6b3a7640000615d4e565b61310d9190615d7b565b6131179190615d4e565b6131219190615d7b565b975061313588670de0b6b3a7640000615c80565b61314785670de0b6b3a7640000615d4e565b6131519190615d7b565b9b9a5050505050505050505050565b60008061316d8a8c615c80565b90508b3473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601613252578083146131b657604051633851fdc960e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561323457600080fd5b505af1158015613248573d6000803e3d6000fd5b5050505050613284565b80156132715760405163ae6d566f60e01b815260040160405180910390fd5b6132848261327d613699565b308661374e565b613294828e8e8e8e8e8e8e61482f565b61329d8b614ae4565b60006132e86132af60208e018e6156b2565b8d60200160208101906132c291906156b2565b8e60400160208101906132d59190615c17565b8f606001602081019061054e91906156b2565b9050851561347e576040516335313c2160e11b81523060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015613336573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061335a9190615c34565b60405163b9a09fd560e01b81526001600160a01b0383811660048301529196506000917f0000000000000000000000000000000000000000000000000000000000000000169063b9a09fd590602401602060405180830381865afa1580156133c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ea9190615cac565b90506134006001600160a01b0383168288614c4c565b604051636e553f6560e01b8152600481018790526001600160a01b038981166024830152821690636e553f6590604401600060405180830381600087803b15801561344a57600080fd5b505af115801561345e573d6000803e3d6000fd5b50613478925050506001600160a01b038316826000614c4c565b506134ed565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af11580156134c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ea9190615c34565b94505b6134f68f614412565b61350b61350660208e018e6156b2565b614412565b61351e61350660408e0160208f016156b2565b505050509a9950505050505050505050565b60008161353c81613675565b61356c897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a610870565b6040516370a0823160e01b81523060048201529093506135e591508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190615c34565b614747565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561364757600080fd5b505af115801561365b573d6000803e3d6000fd5b505050506136698483613c6f565b50979650505050505050565b4281101561369657604051630407b05b60e31b815260040160405180910390fd5b50565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036136d8575060131936013560601c90565b503390565b6040516001600160a01b03808516602483015283166044820152606481018290526137489085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614d66565b50505050565b6000846001600160a01b03163b1161376557600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916137c99190615ed7565b6000604051808303816000865af19150503d8060008114613806576040519150601f19603f3d011682016040523d82523d6000602084013e61380b565b606091505b50915091508180156138355750805115806138355750808060200190518101906138359190615c4d565b61383e57600080fd5b505050505050565b815160005b8181101561374857600061389985838151811061386a5761386a615bdd565b60200260200101516000015186848151811061388857613888615bdd565b6020026020010151602001516111c8565b509050600061391e8684815181106138b3576138b3615bdd565b6020026020010151600001518785815181106138d1576138d1615bdd565b6020026020010151602001518886815181106138ef576138ef615bdd565b60200260200101516040015189878151811061390d5761390d615bdd565b602002602001015160600151611779565b905060008060006139a589878151811061393a5761393a615bdd565b6020026020010151600001518a888151811061395857613958615bdd565b6020026020010151602001518b898151811061397657613976615bdd565b6020026020010151604001518c8a8151811061399457613994615bdd565b602002602001015160600151611de8565b509050808987815181106139bb576139bb615bdd565b6020908102919091010151516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa158015613a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a329190615c34565b613a3c9190615bca565b925050826001600160a01b031663f140a35a838a8881518110613a6157613a61615bdd565b6020026020010151600001516040518363ffffffff1660e01b8152600401613a9c9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613ab9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613add9190615c34565b9050600080856001600160a01b03168a8881518110613afe57613afe615bdd565b6020026020010151600001516001600160a01b031614613b2057826000613b24565b6000835b91509150600060018b51613b389190615bca565b8810613b445789613be1565b613be18b613b538a6001615c80565b81518110613b6357613b63615bdd565b6020026020010151600001518c8a6001613b7d9190615c80565b81518110613b8d57613b8d615bdd565b6020026020010151602001518d8b6001613ba79190615c80565b81518110613bb757613bb7615bdd565b6020026020010151604001518e8c6001613bd19190615c80565b8151811061390d5761390d615bdd565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f90613c239086908690869060248101615f1f565b600060405180830381600087803b158015613c3d57600080fd5b505af1158015613c51573d6000803e3d6000fd5b50505050505050505050508080613c6790615c93565b91505061384b565b604080516000808252602082019092526001600160a01b038416908390604051613c999190615ed7565b60006040518083038185875af1925050503d8060008114613cd6576040519150601f19603f3d011682016040523d82523d6000602084013e613cdb565b606091505b5050905080613cfd5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b815160005b81811015613f5b576000613d2685838151811061386a5761386a615bdd565b509050600086613d37846001615c80565b81518110613d4757613d47615bdd565b60200260200101519050600080836001600160a01b0316888681518110613d7057613d70615bdd565b6020026020010151600001516001600160a01b031614613d9257826000613d96565b6000835b91509150600060018951613daa9190615bca565b8610613db65787613e43565b613e4389613dc5886001615c80565b81518110613dd557613dd5615bdd565b6020026020010151600001518a886001613def9190615c80565b81518110613dff57613dff615bdd565b6020026020010151602001518b896001613e199190615c80565b81518110613e2957613e29615bdd565b6020026020010151604001518c8a6001613bd19190615c80565b9050613eb4898781518110613e5a57613e5a615bdd565b6020026020010151600001518a8881518110613e7857613e78615bdd565b6020026020010151602001518b8981518110613e9657613e96615bdd565b6020026020010151604001518c8a8151811061390d5761390d615bdd565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613ef1576020820181803683370190505b506040518563ffffffff1660e01b8152600401613f119493929190615f1f565b600060405180830381600087803b158015613f2b57600080fd5b505af1158015613f3f573d6000803e3d6000fd5b5050505050505050508080613f5390615c93565b915050613d07565b5050505050565b60008083861015613f8657604051636e35977960e11b815260040160405180910390fd5b82851015613fa75760405163acee051360e01b815260040160405180910390fd5b6040516306801cc360e41b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636801cc3090613ffa908d908d908d90600401615d2a565b602060405180830381865afa158015614017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403b9190615cac565b90506001600160a01b0381166140e1576040516320b7f73960e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906382dfdce49061409b908d908d908d90600401615d2a565b6020604051808303816000875af11580156140ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140de9190615cac565b90505b6000806141108c8c8c7f0000000000000000000000000000000000000000000000000000000000000000611de8565b91509150816000148015614122575080155b15614132578894508793506141bc565b600061413f8a84846146cc565b9050888111614174578681101561416957604051630d32418960e21b815260040160405180910390fd5b8995509350836141ba565b60006141818a84866146cc565b90508a81111561419357614193615c6a565b888110156141b4576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b60006141da60208301836156b2565b905060006141ee60408401602085016156b2565b9050600061421783836142076060880160408901615c17565b61054e6080890160608a016156b2565b905061422e6001600160a01b0382163383886136dd565b600061423a84846111c8565b5060405163226bf2d160e21b815230600482015290915060009081906001600160a01b038516906389afcb449060240160408051808303816000875af1158015614288573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ac9190615bf3565b91509150600080846001600160a01b0316886001600160a01b0316146142d35782846142d6565b83835b915091508860c001358210156142ff576040516323d9bb0560e21b815260040160405180910390fd5b8860e0013581101561432457604051630d32418960e21b815260040160405180910390fd5b50505050505050505050565b600061433c8483611253565b905082816001835161434e9190615bca565b8151811061435e5761435e615bdd565b60200260200101511015614385576040516342301c2360e01b815260040160405180910390fd5b60006143fa8360008151811061439d5761439d615bdd565b602002602001015160000151846000815181106143bc576143bc615bdd565b602002602001015160200151856000815181106143db576143db615bdd565b6020026020010151604001518660008151811061390d5761390d615bdd565b9050614407868287614747565b61383e828430613d02565b600061441c613699565b9050600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601614559576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156144a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144cd9190615c34565b90508015613cfd57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561453757600080fd5b505af115801561454b573d6000803e3d6000fd5b50505050613cfd8282613c6f565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561459d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c19190615c34565b90508015613cfd57613cfd6001600160a01b0384168383614e38565b6000816000036145ef57506000919050565b600060016145fc84614e68565b901c6001901b9050600181848161461557614615615d65565b048201901c9050600181848161462d5761462d615d65565b048201901c9050600181848161464557614645615d65565b048201901c9050600181848161465d5761465d615d65565b048201901c9050600181848161467557614675615d65565b048201901c9050600181848161468d5761468d615d65565b048201901c905060018184816146a5576146a5615d65565b048201901c90506146c5818285816146bf576146bf615d65565b0461472d565b9392505050565b6000836000036146ef57604051632ca2f52b60e11b815260040160405180910390fd5b8215806146fa575081155b156147185760405163bb55fd2760e01b815260040160405180910390fd5b826147238386615d4e565b611c5f9190615d7b565b600081831061473c578161473e565b825b90505b92915050565b6000836001600160a01b03163b1161475e57600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916147ba9190615ed7565b6000604051808303816000865af19150503d80600081146147f7576040519150601f19603f3d011682016040523d82523d6000602084013e6147fc565b606091505b50915091508180156148265750805115806148265750808060200190518101906148269190615c4d565b613f5b57600080fd5b600061483e60208701876156b2565b9050600061485260408801602089016156b2565b905060006148666060890160408a01615c17565b9050600061487a60808a0160608b016156b2565b9050600061488a85858585611779565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156148cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f19190615cfc565b50915091506103e88211158061490957506103e88111155b15614927576040516302721e1f60e61b815260040160405180910390fd5b5050846001600160a01b03168d6001600160a01b0316146149ff576001600160a01b0385168989614959600182615bca565b81811061496857614968615bdd565b905060800201602001602081019061498091906156b2565b6001600160a01b0316146149a7576040516309d41c6760e31b815260040160405180910390fd5b6149ff8d8d8c608001358c8c808060200260200160405190810160405280939291908181526020016000905b82821015612344576149f060808302860136819003810190615b98565b815260200190600101906149d3565b836001600160a01b03168d6001600160a01b031614614ad5576001600160a01b0384168787614a2f600182615bca565b818110614a3e57614a3e615bdd565b9050608002016020016020810190614a5691906156b2565b6001600160a01b031614614a7d576040516332b2410360e21b815260040160405180910390fd5b614ad58d8c8c60a001358a8a808060200260200160405190810160405280939291908181526020016000905b8282101561234457614ac660808302860136819003810190615b98565b81526020019060010190614aa9565b50505050505050505050505050565b6000614af360208301836156b2565b90506000614b0760408401602085016156b2565b90506000614b1b6060850160408601615c17565b90506000614b2f60808601606087016156b2565b90506000614b3f85858585611779565b6040516370a0823160e01b81523060048201529091506000908190614c329088908890889088906001600160a01b038516906370a0823190602401602060405180830381865afa158015614b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bbb9190615c34565b6040516370a0823160e01b81523060048201526001600160a01b038d16906370a0823190602401602060405180830381865afa158015614bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c239190615c34565b8e60c001358f60e00135614efc565b91509150614c41878484614747565b610ccd868483614747565b801580614cc65750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614ca0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cc49190615c34565b155b614d365760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084015b60405180910390fd5b6040516001600160a01b038316602482015260448101829052613cfd90849063095ea7b360e01b90606401613711565b6000614dbb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661500b9092919063ffffffff16565b805190915015613cfd5780806020019051810190614dd99190615c4d565b613cfd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401614d2d565b6040516001600160a01b038316602482015260448101829052613cfd90849063a9059cbb60e01b90606401613711565b600080608083901c15614e7d57608092831c92015b604083901c15614e8f57604092831c92015b602083901c15614ea157602092831c92015b601083901c15614eb357601092831c92015b600883901c15614ec557600892831c92015b600483901c15614ed757600492831c92015b600283901c15614ee957600292831c92015b600183901c156147415760010192915050565b60008083861015614f2057604051636e35977960e11b815260040160405180910390fd5b82851015614f415760405163acee051360e01b815260040160405180910390fd5b600080614f508c8c8c8c611de8565b91509150816000148015614f62575080155b15614f7257879350869250614ffc565b6000614f7f8984846146cc565b9050878111614fb45785811015614fa957604051630d32418960e21b815260040160405180910390fd5b889450925082614ffa565b6000614fc18984866146cc565b905089811115614fd357614fd3615c6a565b87811015614ff4576040516323d9bb0560e21b815260040160405180910390fd5b94508793505b505b50509850989650505050505050565b6060611c5f848460008585600080866001600160a01b031685876040516150329190615ed7565b60006040518083038185875af1925050503d806000811461506f576040519150601f19603f3d011682016040523d82523d6000602084013e615074565b606091505b509150915061508587838387615090565b979650505050505050565b606083156150ff5782516000036150f8576001600160a01b0385163b6150f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401614d2d565b5081611c5f565b611c5f83838151156151145781518083602001fd5b8060405162461bcd60e51b8152600401614d2d9190615f56565b6001600160a01b038116811461369657600080fd5b803561514e8161512e565b919050565b801515811461369657600080fd5b60008083601f84011261517357600080fd5b5081356001600160401b0381111561518a57600080fd5b6020830191508360208260071b850101111561124c57600080fd5b6000806000806000806000806000806101008b8d0312156151c557600080fd5b8a356151d08161512e565b995060208b01356151e08161512e565b985060408b01356151f081615153565b975060608b01356152008161512e565b965060808b0135955060a08b0135945060c08b01356001600160401b038082111561522a57600080fd5b6152368e838f01615161565b909650945060e08d013591508082111561524f57600080fd5b5061525c8d828e01615161565b915080935050809150509295989b9194979a5092959850565b600080600080600080600080610100898b03121561529257600080fd5b883561529d8161512e565b975060208901356152ad8161512e565b965060408901356152bd81615153565b9550606089013594506080890135935060a0890135925060c08901356152e28161512e565b8092505060e089013590509295985092959890939650565b60008060008060008060a0878903121561531357600080fd5b863595506020870135945060408701356001600160401b0381111561533757600080fd5b61534389828a01615161565b90955093505060608701356153578161512e565b80925050608087013590509295509295509295565b60008060008060006080868803121561538457600080fd5b8535945060208601356001600160401b038111156153a157600080fd5b6153ad88828901615161565b90955093505060408601356153c18161512e565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615410576154106153d2565b604052919050565b60006001600160401b03821115615431576154316153d2565b5060051b60200190565b60008060008060006080868803121561545357600080fd5b85356001600160401b038082111561546a57600080fd5b818801915088601f83011261547e57600080fd5b8135602061549361548e83615418565b6153e8565b82815260059290921b8401810191818101908c8411156154b257600080fd5b948201945b838610156154d0578535825294820194908201906154b7565b995050890135925050808211156154e657600080fd5b506154f388828901615161565b90955093506153c1905060408701615143565b6020808252825182820181905260009190848201906040850190845b8181101561553e57835183529284019291840191600101615522565b50909695505050505050565b6000806040838503121561555d57600080fd5b82356155688161512e565b915060208301356155788161512e565b809150509250929050565b60006080828403121561559557600080fd5b604051608081018181106001600160401b03821117156155b7576155b76153d2565b60405290508082356155c88161512e565b815260208301356155d88161512e565b602082015260408301356155eb81615153565b604082015260608301356155fe8161512e565b6060919091015292915050565b6000806040838503121561561e57600080fd5b823591506020808401356001600160401b0381111561563c57600080fd5b8401601f8101861361564d57600080fd5b803561565b61548e82615418565b81815260079190911b8201830190838101908883111561567a57600080fd5b928401925b828410156156a3576156918985615583565b8252848201915060808401935061567f565b80955050505050509250929050565b6000602082840312156156c457600080fd5b81356146c58161512e565b60008060008060008060008060006101208a8c0312156156ee57600080fd5b89356156f98161512e565b985060208a01356157098161512e565b975060408a013561571981615153565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356157458161512e565b809250506101008a013590509295985092959850929598565b600080600080600080600080600060e08a8c03121561577c57600080fd5b89356157878161512e565b985060208a01356157978161512e565b975060408a01356157a781615153565b965060608a01356157b78161512e565b955060808a0135945060a08a01356001600160401b03808211156157da57600080fd5b6157e68d838e01615161565b909650945060c08c01359150808211156157ff57600080fd5b5061580c8c828d01615161565b915080935050809150509295985092959850929598565b6000806000806080858703121561583957600080fd5b84356158448161512e565b935060208501356158548161512e565b9250604085013561586481615153565b915060608501356158748161512e565b939692955090935050565b6000610100828403121561589257600080fd5b50919050565b6000806000806000806000610180888a0312156158b457600080fd5b87356158bf8161512e565b9650602088013595506158d58960408a0161587f565b94506101408801356001600160401b03808211156158f257600080fd5b6158fe8b838c01615161565b90965094506101608a013591508082111561591857600080fd5b506159258a828b01615161565b989b979a50959850939692959293505050565b600080600080600080600060e0888a03121561595357600080fd5b873561595e8161512e565b9650602088013561596e81615153565b955060408801359450606088013593506080880135925060a08801356159938161512e565b8092505060c0880135905092959891949750929550565b600080600080600060a086880312156159c257600080fd5b85356159cd8161512e565b945060208601356159dd8161512e565b935060408601356159ed81615153565b925060608601356159fd8161512e565b949793965091946080013592915050565b60008060008060008060c08789031215615a2757600080fd5b8635615a328161512e565b95506020870135615a428161512e565b94506040870135615a5281615153565b93506060870135615a628161512e565b9598949750929560808101359460a0909101359350915050565b600080600060608486031215615a9157600080fd5b8335615a9c8161512e565b92506020840135615aac8161512e565b91506040840135615abc8161512e565b809150509250925092565b6000806000806000806000806000806101e08b8d031215615ae757600080fd5b8a35615af28161512e565b995060208b0135985060408b01359750615b0f8c60608d0161587f565b96506101608b01356001600160401b0380821115615b2c57600080fd5b615b388e838f01615161565b90985096506101808d0135915080821115615b5257600080fd5b50615b5f8d828e01615161565b9095509350506101a08b0135615b748161512e565b91506101c08b0135615b8581615153565b809150509295989b9194979a5092959850565b600060808284031215615baa57600080fd5b61473e8383615583565b634e487b7160e01b600052601160045260246000fd5b8181038181111561474157614741615bb4565b634e487b7160e01b600052603260045260246000fd5b60008060408385031215615c0657600080fd5b505080516020909101519092909150565b600060208284031215615c2957600080fd5b81356146c581615153565b600060208284031215615c4657600080fd5b5051919050565b600060208284031215615c5f57600080fd5b81516146c581615153565b634e487b7160e01b600052600160045260246000fd5b8082018082111561474157614741615bb4565b600060018201615ca557615ca5615bb4565b5060010190565b600060208284031215615cbe57600080fd5b81516146c58161512e565b6bffffffffffffffffffffffff19606094851b811682529290931b9091166014830152151560f81b602882015260290190565b600080600060608486031215615d1157600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152901515604082015260600190565b808202811582820484141761474157614741615bb4565b634e487b7160e01b600052601260045260246000fd5b600082615d9857634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615daf57600080fd5b815160ff811681146146c557600080fd5b600181815b80851115615dfb578160001904821115615de157615de1615bb4565b80851615615dee57918102915b93841c9390800290615dc5565b509250929050565b600082615e1257506001614741565b81615e1f57506000614741565b8160018114615e355760028114615e3f57615e5b565b6001915050614741565b60ff841115615e5057615e50615bb4565b50506001821b614741565b5060208310610133831016604e8410600b8410161715615e7e575081810a614741565b615e888383615dc0565b8060001904821115615e9c57615e9c615bb4565b029392505050565b600061473e60ff841683615e03565b60005b83811015615ece578181015183820152602001615eb6565b50506000910152565b60008251615ee9818460208701615eb3565b9190910192915050565b60008151808452615f0b816020860160208601615eb3565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b0383166040820152608060608201526000615f4c6080830184615ef3565b9695505050505050565b60208152600061473e6020830184615ef356fea2646970667358221220b1099ee7ddb5dc2ea1ec270042b192b9761fe430654308578bf270f4f8bb35cd64736f6c6343000813003300000000000000000000000006824df38d1d77eadeb6bafcb03904e27429ab74000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b00000000000000000000000025cbddb98b35ab1ff77413456b31ec81a6b6b746000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c0000000000000000000000004200000000000000000000000000000000000006
Deployed Bytecode
0x6080604052600436106101dc5760003560e01c8063874029d911610102578063cac88ea911610095578063e4ea9d7411610064578063e4ea9d74146106ad578063f5ba53c7146106cd578063fb49bafd146106fb578063fe411f141461070e57600080fd5b8063cac88ea914610619578063ce700c2914610639578063d4b6846d14610659578063d7b0e0a51461068d57600080fd5b8063a81b9159116100d1578063a81b9159146105a6578063b7e0d4c0146105c6578063c6b7f1b6146105d9578063c92de3ec146105f957600080fd5b8063874029d91461053357806388cd821e146105535780638c0037dc14610573578063903638a41461059357600080fd5b806342cb1fbc1161017a578063572b6c0511610149578063572b6c05146104475780635a47ddc3146104a45780637539d413146104df5780638083f7bb146104ff57600080fd5b806342cb1fbc1461038b57806346c96aac146103b3578063544caa56146103e75780635509a1ac1461042757600080fd5b80633bf0c9fb116101b65780633bf0c9fb146102cb5780633da5acba146103175780633fc8cef31461032a5780634111d5971461035e57600080fd5b806307db50fa146102315780630dede6c41461027657806312bc3aca146102ab57600080fd5b3661022c57336001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006161461022a576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561023d57600080fd5b5061025161024c3660046151a5565b61072e565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561028257600080fd5b50610296610291366004615275565b610870565b6040805192835260208301919091520161026d565b3480156102b757600080fd5b5061022a6102c63660046152fa565b6109c9565b3480156102d757600080fd5b506102ff7f000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b81565b6040516001600160a01b03909116815260200161026d565b61022a61032536600461536c565b610cd7565b34801561033657600080fd5b506102ff7f000000000000000000000000420000000000000000000000000000000000000681565b34801561036a57600080fd5b5061037e61037936600461543b565b611068565b60405161026d9190615506565b34801561039757600080fd5b506102ff73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b3480156103bf57600080fd5b506102ff7f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c81565b3480156103f357600080fd5b5061040761040236600461554a565b6111c8565b604080516001600160a01b0393841681529290911660208301520161026d565b34801561043357600080fd5b5061037e61044236600461560b565b611253565b34801561045357600080fd5b506104946104623660046156b2565b7f00000000000000000000000006824df38d1d77eadeb6bafcb03904e27429ab746001600160a01b0390811691161490565b604051901515815260200161026d565b3480156104b057600080fd5b506104c46104bf3660046156cf565b611548565b6040805193845260208401929092529082015260600161026d565b3480156104eb57600080fd5b506102516104fa36600461575e565b611640565b34801561050b57600080fd5b506102ff7f00000000000000000000000025cbddb98b35ab1ff77413456b31ec81a6b6b74681565b34801561053f57600080fd5b506102ff61054e366004615823565b611779565b34801561055f57600080fd5b5061022a61056e3660046152fa565b611c67565b34801561057f57600080fd5b5061029661058e366004615823565b611de8565b61037e6105a136600461536c565b611ea2565b3480156105b257600080fd5b5061022a6105c1366004615898565b612183565b6104c46105d4366004615938565b6124a4565b3480156105e557600080fd5b5061037e6105f43660046152fa565b6126f6565b34801561060557600080fd5b506102966106143660046159aa565b6129bd565b34801561062557600080fd5b5061037e6106343660046152fa565b612b06565b34801561064557600080fd5b506104c4610654366004615a0e565b612c15565b34801561066557600080fd5b506102ff7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a81565b34801561069957600080fd5b506102966106a8366004615938565b612df7565b3480156106b957600080fd5b506102ff6106c8366004615823565b612ed5565b3480156106d957600080fd5b506106ed6106e8366004615a7c565b612eec565b60405190815260200161026d565b6106ed610709366004615ac7565b613160565b34801561071a57600080fd5b506106ed610729366004615938565b613530565b8585600080606087156107c3576107978b8a8a808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761077e60808302860136819003810190615b98565b81526020019060010190610761565b5050505050611253565b905080600182516107a89190615bca565b815181106107b8576107b8615bdd565b602002602001015194505b85156108475761081b8a8888808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761080c60808302860136819003810190615b98565b815260200190600101906107ef565b9050806001825161082c9190615bca565b8151811061083c5761083c615bdd565b602002602001015193505b6108558f8f8f8f8989612c15565b508093508194505050509a509a509a509a9650505050505050565b6000808261087d81613675565b60006108ab8c8c8c7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a611779565b90506108ca6108b8613699565b6001600160a01b03831690838c6136dd565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015610916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093a9190615bf3565b91509150600061094a8f8f6111c8565b509050806001600160a01b03168f6001600160a01b03161461096d578183610970565b82825b90975095508a871015610996576040516323d9bb0560e21b815260040160405180910390fd5b898610156109b757604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b806109d381613675565b6001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006168585610a0a600182615bca565b818110610a1957610a19615bdd565b9050608002016020016020810190610a3191906156b2565b6001600160a01b031614610a58576040516320db826760e01b815260040160405180910390fd5b610b3f85856000818110610a6e57610a6e615bdd565b610a8492602060809092020190810191506156b2565b610a8c613699565b610b3988886000818110610aa257610aa2615bdd565b610ab892602060809092020190810191506156b2565b89896000818110610acb57610acb615bdd565b9050608002016020016020810190610ae391906156b2565b8a8a6000818110610af657610af6615bdd565b9050608002016040016020810190610b0e9190615c17565b8b8b6000818110610b2157610b21615bdd565b905060800201606001602081019061054e91906156b2565b8a61374e565b610b9b8585808060200260200160405190810160405280939291908181526020016000905b82821015610b9057610b8160808302860136819003810190615b98565b81526020019060010190610b64565b505050505030613846565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316906370a0823190602401602060405180830381865afa158015610c02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c269190615c34565b905086811015610c49576040516342301c2360e01b815260040160405180910390fd5b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610cab57600080fd5b505af1158015610cbf573d6000803e3d6000fd5b50505050610ccd8482613c6f565b5050505050505050565b80610ce181613675565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031685856000818110610d1e57610d1e615bdd565b610d3492602060809092020190810191506156b2565b6001600160a01b031614610d5b576040516320db826760e01b815260040160405180910390fd5b60003490507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb610e1988886000818110610aa257610aa2615bdd565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610e66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8a9190615c4d565b610e9657610e96615c6a565b6000610ea3600187615bca565b90506000878783818110610eb957610eb9615bdd565b9050608002016020016020810190610ed191906156b2565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190615c34565b9050610f9b8888808060200260200160405190810160405280939291908181526020016000905b82821015610f9057610f8160808302860136819003810190615b98565b81526020019060010190610f64565b505050505087613846565b8881898985818110610faf57610faf615bdd565b9050608002016020016020810190610fc791906156b2565b6040516370a0823160e01b81526001600160a01b038a8116600483015291909116906370a08231906024015b602060405180830381865afa158015611010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110349190615c34565b61103e9190615bca565b101561105d576040516342301c2360e01b815260040160405180910390fd5b505050505050505050565b60608161107481613675565b61115d8686600081811061108a5761108a615bdd565b6110a092602060809092020190810191506156b2565b6110a8613699565b61113d898960008181106110be576110be615bdd565b6110d492602060809092020190810191506156b2565b8a8a60008181106110e7576110e7615bdd565b90506080020160200160208101906110ff91906156b2565b8b8b600081811061111257611112615bdd565b905060800201604001602081019061112a9190615c17565b8c8c6000818110610b2157610b21615bdd565b8a60008151811061115057611150615bdd565b602002602001015161374e565b6111ba878787808060200260200160405190810160405280939291908181526020016000905b828210156111af576111a060808302860136819003810190615b98565b81526020019060010190611183565b505050505086613d02565b8691505b5095945050505050565b600080826001600160a01b0316846001600160a01b0316036111fd57604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b03161061121d578284611220565b83835b90925090506001600160a01b03821661124c5760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b6060600182511015611278576040516320db826760e01b815260040160405180910390fd5b8151611285906001615c80565b6001600160401b0381111561129c5761129c6153d2565b6040519080825280602002602001820160405280156112c5578160200160208202803683370190505b50905082816000815181106112dc576112dc615bdd565b6020908102919091010152815160005b81811015611540576000806001600160a01b031685838151811061131257611312615bdd565b6020026020010151606001516001600160a01b03161461134f5784828151811061133e5761133e615bdd565b602002602001015160600151611371565b7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a5b905060006113d886848151811061138a5761138a615bdd565b6020026020010151600001518785815181106113a8576113a8615bdd565b6020026020010151602001518886815181106113c6576113c6615bdd565b60200260200101516040015185611779565b60405163e5e31b1360e01b81526001600160a01b0380831660048301529192509083169063e5e31b1390602401602060405180830381865afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114469190615c4d565b1561152b57806001600160a01b031663f140a35a86858151811061146c5761146c615bdd565b602002602001015188868151811061148657611486615bdd565b6020026020010151600001516040518363ffffffff1660e01b81526004016114c19291909182526001600160a01b0316602082015260400190565b602060405180830381865afa1580156114de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115029190615c34565b8561150e856001615c80565b8151811061151e5761151e615bdd565b6020026020010181815250505b5050808061153890615c93565b9150506112ec565b505092915050565b60008060008361155781613675565b6115668d8d8d8d8d8d8d613f62565b909450925060006115998e8e8e7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a611779565b90506115ae8e6115a7613699565b838861374e565b6115c18d6115ba613699565b838761374e565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af1158015611609573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162d9190615c34565b9250505099509950999650505050505050565b6000806000806116538d8d8d8d8d6129bd565b9094509250839150829050606087156116e4576116b8838a8a808060200260200160405190810160405280939291908181526020016000905b8282101561078d576116a960808302860136819003810190615b98565b8152602001906001019061168c565b905080600182516116c99190615bca565b815181106116d9576116d9615bdd565b602002602001015194505b85156117685761173c828888808060200260200160405190810160405280939291908181526020016000905b8282101561078d5761172d60808302860136819003810190615b98565b81526020019060010190611710565b9050806001825161174d9190615bca565b8151811061175d5761175d615bdd565b602002602001015193505b509950995099509995505050505050565b60007f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a816001600160a01b038416156117b257836117b4565b815b60405163d1ea0a1d60e01b81526001600160a01b0380831660048301529192507f000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b9091169063d1ea0a1d90602401602060405180830381865afa15801561181f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118439190615c4d565b61186057604051634d39d5a360e11b815260040160405180910390fd5b6000826001600160a01b0316638c7c53ce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c49190615cac565b90506000836001600160a01b031663c6751c096040518163ffffffff1660e01b8152600401602060405180830381865afa158015611906573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192a9190615cac565b9050806001600160a01b0316896001600160a01b031614801561195e5750816001600160a01b0316886001600160a01b0316145b1561197c57604051639cda859960e01b815260040160405180910390fd5b816001600160a01b0316896001600160a01b03161480156119ae5750806001600160a01b0316886001600160a01b0316145b15611a2057836001600160a01b0316638e39ee166040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a159190615cac565b945050505050611c5f565b600080611a2d8b8b6111c8565b915091507f00000000000000000000000025cbddb98b35ab1ff77413456b31ec81a6b6b7466001600160a01b0316856001600160a01b031614611b6357600082828b604051602001611a8193929190615cc9565b604051602081830303815290604052805190602001209050611b5b866001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ada573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afe9190615cac565b604051603881018990526f5af43d82803e903d91602b57fd5bf3ff60248201526014810191909152733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018390526037600c8201206078820152605560439091012090565b975050611c58565b6000856001600160a01b0316639aab92486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc79190615c34565b90508583838c604051602001611bdf93929190615cc9565b6040516020818303038152906040528051906020012082604051602001611c3b939291906001600160f81b0319815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b6040516020818303038152906040528051906020012060001c9750505b5050505050505b949350505050565b80611c7181613675565b611c8785856000818110610a6e57610a6e615bdd565b6000611c94600186615bca565b90506000868683818110611caa57611caa615bdd565b9050608002016020016020810190611cc291906156b2565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a0823190602401602060405180830381865afa158015611d0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2e9190615c34565b9050611d8c8787808060200260200160405190810160405280939291908181526020016000905b82821015611d8157611d7260808302860136819003810190615b98565b81526020019060010190611d55565b505050505086613846565b8781888885818110611da057611da0615bdd565b9050608002016020016020810190611db891906156b2565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401610ff3565b6000806000611df787876111c8565b509050600080611e0989898989611779565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6a9190615cfc565b5091509150826001600160a01b0316896001600160a01b031614611e8f578082611e92565b81815b909a909950975050505050505050565b606081611eae81613675565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031686866000818110611eeb57611eeb615bdd565b611f0192602060809092020190810191506156b2565b6001600160a01b031614611f28576040516320db826760e01b815260040160405180910390fd5b611f7a348787808060200260200160405190810160405280939291908181526020016000905b8282101561078d57611f6b60808302860136819003810190615b98565b81526020019060010190611f4e565b9150868260018451611f8c9190615bca565b81518110611f9c57611f9c615bdd565b60200260200101511015611fc3576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db08360008151811061200557612005615bdd565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561203857600080fd5b505af115801561204c573d6000803e3d6000fd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb61209688886000818110610aa257610aa2615bdd565b846000815181106120a9576120a9615bdd565b60200260200101516040518363ffffffff1660e01b81526004016120e29291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121259190615c4d565b61213157612131615c6a565b6111be828787808060200260200160405190810160405280939291908181526020016000905b828210156111af5761217460808302860136819003810190615b98565b81526020019060010190612157565b600061219260208701876156b2565b905060006121a660408801602089016156b2565b905060006001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146121d457896121f6565b7f00000000000000000000000042000000000000000000000000000000000000065b905061220289896141cb565b6000816001600160a01b0316846001600160a01b03161461234e576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122859190615c34565b90506001600160a01b038216888861229e600182615bca565b8181106122ad576122ad615bdd565b90506080020160200160208101906122c591906156b2565b6001600160a01b0316146122ec576040516309d41c6760e31b815260040160405180910390fd5b61234e84828b608001358b8b808060200260200160405190810160405280939291908181526020016000905b828210156123445761233560808302860136819003810190615b98565b81526020019060010190612318565b5050505050614330565b816001600160a01b0316836001600160a01b03161461248e576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156123ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cf9190615c34565b90506001600160a01b03821686866123e8600182615bca565b8181106123f7576123f7615bdd565b905060800201602001602081019061240f91906156b2565b6001600160a01b031614612436576040516332b2410360e21b815260040160405180910390fd5b61248e83828b60a001358989808060200260200160405190810160405280939291908181526020016000905b828210156123445761247f60808302860136819003810190615b98565b81526020019060010190612462565b6124978b614412565b5050505050505050505050565b6000806000836124b381613675565b6124e28b7f00000000000000000000000042000000000000000000000000000000000000068c8c348d8d613f62565b909450925060006125358c7f00000000000000000000000042000000000000000000000000000000000000068d7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a611779565b90506125438c6115a7613699565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561259e57600080fd5b505af11580156125b2573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000420000000000000000000000000000000000000616935063a9059cbb925060440190506020604051808303816000875af1158015612627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264b9190615c4d565b61265757612657615c6a565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561269f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c39190615c34565b9250833411156126e7576126e76126d8613699565b6126e28634615bca565b613c6f565b50509750975097945050505050565b60608161270281613675565b6001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006168686612739600182615bca565b81811061274857612748615bdd565b905060800201602001602081019061276091906156b2565b6001600160a01b031614612787576040516320db826760e01b815260040160405180910390fd5b6127d9888787808060200260200160405190810160405280939291908181526020016000905b8282101561078d576127ca60808302860136819003810190615b98565b815260200190600101906127ad565b91508682600184516127eb9190615bca565b815181106127fb576127fb615bdd565b60200260200101511015612822576040516342301c2360e01b815260040160405180910390fd5b61287f8686600081811061283857612838615bdd565b61284e92602060809092020190810191506156b2565b612856613699565b61286c898960008181106110be576110be615bdd565b8560008151811061115057611150615bdd565b6128dc828787808060200260200160405190810160405280939291908181526020016000905b828210156128d1576128c260808302860136819003810190615b98565b815260200190600101906128a5565b505050505030613d02565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316632e1a7d4d836001855161291a9190615bca565b8151811061292a5761292a615bdd565b60200260200101516040518263ffffffff1660e01b815260040161295091815260200190565b600060405180830381600087803b15801561296a57600080fd5b505af115801561297e573d6000803e3d6000fd5b505050506129b28483600185516129959190615bca565b815181106129a5576129a5615bdd565b6020026020010151613c6f565b509695505050505050565b6000806000846001600160a01b0316636801cc308989896040518463ffffffff1660e01b81526004016129f293929190615d2a565b602060405180830381865afa158015612a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a339190615cac565b90506001600160a01b038116612a50576000809250925050612afc565b600080612a5f8a8a8a8a611de8565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac79190615c34565b905080612ad48489615d4e565b612ade9190615d7b565b955080612aeb8389615d4e565b612af59190615d7b565b9450505050505b9550959350505050565b606081612b1281613675565b612b64888787808060200260200160405190810160405280939291908181526020016000905b8282101561078d57612b5560808302860136819003810190615b98565b81526020019060010190612b38565b9150868260018451612b769190615bca565b81518110612b8657612b86615bdd565b60200260200101511015612bad576040516342301c2360e01b815260040160405180910390fd5b612bc38686600081811061283857612838615bdd565b6129b2828787808060200260200160405190810160405280939291908181526020016000905b828210156111af57612c0660808302860136819003810190615b98565b81526020019060010190612be9565b600080600080866001600160a01b0316636801cc308b8b8b6040518463ffffffff1660e01b8152600401612c4b93929190615d2a565b602060405180830381865afa158015612c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8c9190615cac565b9050600080806001600160a01b03841615612d1757836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d039190615c34565b9050612d118d8d8d8d611de8565b90935091505b82158015612d23575081155b15612d54578896508795506103e8612d43612d3e888a615d4e565b6145dd565b612d4d9190615bca565b9450612de7565b6000612d618a85856146cc565b9050888111612da957899750955085612da284612d7e848b615d4e565b612d889190615d7b565b84612d93858b615d4e565b612d9d9190615d7b565b61472d565b9550612de5565b6000612db68a85876146cc565b9850899750889050612de185612dcc8584615d4e565b612dd69190615d7b565b85612d93868c615d4e565b9650505b505b5050505096509650969350505050565b60008082612e0481613675565b612e348a7f00000000000000000000000042000000000000000000000000000000000000068b8b8b8b308b610870565b9093509150612e448a8685614747565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612ea657600080fd5b505af1158015612eba573d6000803e3d6000fd5b50505050612ec88583613c6f565b5097509795505050505050565b6000612ee385858585611779565b95945050505050565b600080612efc8585600186611779565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f629190615d9d565b612f6d90600a615ea4565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd39190615d9d565b612fde90600a615ea4565b6040516378a051ad60e11b8152600481018490526001600160a01b03898116602483015291925083916000919086169063f140a35a90604401602060405180830381865afa158015613034573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130589190615c34565b905060008061306c8b8b60018c8888612c15565b5090925090508561308583670de0b6b3a7640000615d4e565b61308f9190615d7b565b9150846130a482670de0b6b3a7640000615d4e565b6130ae9190615d7b565b9050846130c384670de0b6b3a7640000615d4e565b6130cd9190615d7b565b9250856130e285670de0b6b3a7640000615d4e565b6130ec9190615d7b565b935080828561310386670de0b6b3a7640000615d4e565b61310d9190615d7b565b6131179190615d4e565b6131219190615d7b565b975061313588670de0b6b3a7640000615c80565b61314785670de0b6b3a7640000615d4e565b6131519190615d7b565b9b9a5050505050505050505050565b60008061316d8a8c615c80565b90508b3473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601613252578083146131b657604051633851fdc960e11b815260040160405180910390fd5b7f000000000000000000000000420000000000000000000000000000000000000691507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561323457600080fd5b505af1158015613248573d6000803e3d6000fd5b5050505050613284565b80156132715760405163ae6d566f60e01b815260040160405180910390fd5b6132848261327d613699565b308661374e565b613294828e8e8e8e8e8e8e61482f565b61329d8b614ae4565b60006132e86132af60208e018e6156b2565b8d60200160208101906132c291906156b2565b8e60400160208101906132d59190615c17565b8f606001602081019061054e91906156b2565b9050851561347e576040516335313c2160e11b81523060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015613336573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061335a9190615c34565b60405163b9a09fd560e01b81526001600160a01b0383811660048301529196506000917f00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c169063b9a09fd590602401602060405180830381865afa1580156133c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ea9190615cac565b90506134006001600160a01b0383168288614c4c565b604051636e553f6560e01b8152600481018790526001600160a01b038981166024830152821690636e553f6590604401600060405180830381600087803b15801561344a57600080fd5b505af115801561345e573d6000803e3d6000fd5b50613478925050506001600160a01b038316826000614c4c565b506134ed565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af11580156134c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ea9190615c34565b94505b6134f68f614412565b61350b61350660208e018e6156b2565b614412565b61351e61350660408e0160208f016156b2565b505050509a9950505050505050505050565b60008161353c81613675565b61356c897f00000000000000000000000042000000000000000000000000000000000000068a8a8a8a308a610870565b6040516370a0823160e01b81523060048201529093506135e591508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa1580156135bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e09190615c34565b614747565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561364757600080fd5b505af115801561365b573d6000803e3d6000fd5b505050506136698483613c6f565b50979650505050505050565b4281101561369657604051630407b05b60e31b815260040160405180910390fd5b50565b60007f00000000000000000000000006824df38d1d77eadeb6bafcb03904e27429ab746001600160a01b031633036136d8575060131936013560601c90565b503390565b6040516001600160a01b03808516602483015283166044820152606481018290526137489085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614d66565b50505050565b6000846001600160a01b03163b1161376557600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916137c99190615ed7565b6000604051808303816000865af19150503d8060008114613806576040519150601f19603f3d011682016040523d82523d6000602084013e61380b565b606091505b50915091508180156138355750805115806138355750808060200190518101906138359190615c4d565b61383e57600080fd5b505050505050565b815160005b8181101561374857600061389985838151811061386a5761386a615bdd565b60200260200101516000015186848151811061388857613888615bdd565b6020026020010151602001516111c8565b509050600061391e8684815181106138b3576138b3615bdd565b6020026020010151600001518785815181106138d1576138d1615bdd565b6020026020010151602001518886815181106138ef576138ef615bdd565b60200260200101516040015189878151811061390d5761390d615bdd565b602002602001015160600151611779565b905060008060006139a589878151811061393a5761393a615bdd565b6020026020010151600001518a888151811061395857613958615bdd565b6020026020010151602001518b898151811061397657613976615bdd565b6020026020010151604001518c8a8151811061399457613994615bdd565b602002602001015160600151611de8565b509050808987815181106139bb576139bb615bdd565b6020908102919091010151516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa158015613a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a329190615c34565b613a3c9190615bca565b925050826001600160a01b031663f140a35a838a8881518110613a6157613a61615bdd565b6020026020010151600001516040518363ffffffff1660e01b8152600401613a9c9291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613ab9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613add9190615c34565b9050600080856001600160a01b03168a8881518110613afe57613afe615bdd565b6020026020010151600001516001600160a01b031614613b2057826000613b24565b6000835b91509150600060018b51613b389190615bca565b8810613b445789613be1565b613be18b613b538a6001615c80565b81518110613b6357613b63615bdd565b6020026020010151600001518c8a6001613b7d9190615c80565b81518110613b8d57613b8d615bdd565b6020026020010151602001518d8b6001613ba79190615c80565b81518110613bb757613bb7615bdd565b6020026020010151604001518e8c6001613bd19190615c80565b8151811061390d5761390d615bdd565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f90613c239086908690869060248101615f1f565b600060405180830381600087803b158015613c3d57600080fd5b505af1158015613c51573d6000803e3d6000fd5b50505050505050505050508080613c6790615c93565b91505061384b565b604080516000808252602082019092526001600160a01b038416908390604051613c999190615ed7565b60006040518083038185875af1925050503d8060008114613cd6576040519150601f19603f3d011682016040523d82523d6000602084013e613cdb565b606091505b5050905080613cfd5760405163b12d13eb60e01b815260040160405180910390fd5b505050565b815160005b81811015613f5b576000613d2685838151811061386a5761386a615bdd565b509050600086613d37846001615c80565b81518110613d4757613d47615bdd565b60200260200101519050600080836001600160a01b0316888681518110613d7057613d70615bdd565b6020026020010151600001516001600160a01b031614613d9257826000613d96565b6000835b91509150600060018951613daa9190615bca565b8610613db65787613e43565b613e4389613dc5886001615c80565b81518110613dd557613dd5615bdd565b6020026020010151600001518a886001613def9190615c80565b81518110613dff57613dff615bdd565b6020026020010151602001518b896001613e199190615c80565b81518110613e2957613e29615bdd565b6020026020010151604001518c8a6001613bd19190615c80565b9050613eb4898781518110613e5a57613e5a615bdd565b6020026020010151600001518a8881518110613e7857613e78615bdd565b6020026020010151602001518b8981518110613e9657613e96615bdd565b6020026020010151604001518c8a8151811061390d5761390d615bdd565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613ef1576020820181803683370190505b506040518563ffffffff1660e01b8152600401613f119493929190615f1f565b600060405180830381600087803b158015613f2b57600080fd5b505af1158015613f3f573d6000803e3d6000fd5b5050505050505050508080613f5390615c93565b915050613d07565b5050505050565b60008083861015613f8657604051636e35977960e11b815260040160405180910390fd5b82851015613fa75760405163acee051360e01b815260040160405180910390fd5b6040516306801cc360e41b81526000906001600160a01b037f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a1690636801cc3090613ffa908d908d908d90600401615d2a565b602060405180830381865afa158015614017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403b9190615cac565b90506001600160a01b0381166140e1576040516320b7f73960e21b81526001600160a01b037f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a16906382dfdce49061409b908d908d908d90600401615d2a565b6020604051808303816000875af11580156140ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140de9190615cac565b90505b6000806141108c8c8c7f000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a611de8565b91509150816000148015614122575080155b15614132578894508793506141bc565b600061413f8a84846146cc565b9050888111614174578681101561416957604051630d32418960e21b815260040160405180910390fd5b8995509350836141ba565b60006141818a84866146cc565b90508a81111561419357614193615c6a565b888110156141b4576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b60006141da60208301836156b2565b905060006141ee60408401602085016156b2565b9050600061421783836142076060880160408901615c17565b61054e6080890160608a016156b2565b905061422e6001600160a01b0382163383886136dd565b600061423a84846111c8565b5060405163226bf2d160e21b815230600482015290915060009081906001600160a01b038516906389afcb449060240160408051808303816000875af1158015614288573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ac9190615bf3565b91509150600080846001600160a01b0316886001600160a01b0316146142d35782846142d6565b83835b915091508860c001358210156142ff576040516323d9bb0560e21b815260040160405180910390fd5b8860e0013581101561432457604051630d32418960e21b815260040160405180910390fd5b50505050505050505050565b600061433c8483611253565b905082816001835161434e9190615bca565b8151811061435e5761435e615bdd565b60200260200101511015614385576040516342301c2360e01b815260040160405180910390fd5b60006143fa8360008151811061439d5761439d615bdd565b602002602001015160000151846000815181106143bc576143bc615bdd565b602002602001015160200151856000815181106143db576143db615bdd565b6020026020010151604001518660008151811061390d5761390d615bdd565b9050614407868287614747565b61383e828430613d02565b600061441c613699565b9050600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601614559576040516370a0823160e01b81523060048201527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316906370a0823190602401602060405180830381865afa1580156144a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144cd9190615c34565b90508015613cfd57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561453757600080fd5b505af115801561454b573d6000803e3d6000fd5b50505050613cfd8282613c6f565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561459d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c19190615c34565b90508015613cfd57613cfd6001600160a01b0384168383614e38565b6000816000036145ef57506000919050565b600060016145fc84614e68565b901c6001901b9050600181848161461557614615615d65565b048201901c9050600181848161462d5761462d615d65565b048201901c9050600181848161464557614645615d65565b048201901c9050600181848161465d5761465d615d65565b048201901c9050600181848161467557614675615d65565b048201901c9050600181848161468d5761468d615d65565b048201901c905060018184816146a5576146a5615d65565b048201901c90506146c5818285816146bf576146bf615d65565b0461472d565b9392505050565b6000836000036146ef57604051632ca2f52b60e11b815260040160405180910390fd5b8215806146fa575081155b156147185760405163bb55fd2760e01b815260040160405180910390fd5b826147238386615d4e565b611c5f9190615d7b565b600081831061473c578161473e565b825b90505b92915050565b6000836001600160a01b03163b1161475e57600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916147ba9190615ed7565b6000604051808303816000865af19150503d80600081146147f7576040519150601f19603f3d011682016040523d82523d6000602084013e6147fc565b606091505b50915091508180156148265750805115806148265750808060200190518101906148269190615c4d565b613f5b57600080fd5b600061483e60208701876156b2565b9050600061485260408801602089016156b2565b905060006148666060890160408a01615c17565b9050600061487a60808a0160608b016156b2565b9050600061488a85858585611779565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156148cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f19190615cfc565b50915091506103e88211158061490957506103e88111155b15614927576040516302721e1f60e61b815260040160405180910390fd5b5050846001600160a01b03168d6001600160a01b0316146149ff576001600160a01b0385168989614959600182615bca565b81811061496857614968615bdd565b905060800201602001602081019061498091906156b2565b6001600160a01b0316146149a7576040516309d41c6760e31b815260040160405180910390fd5b6149ff8d8d8c608001358c8c808060200260200160405190810160405280939291908181526020016000905b82821015612344576149f060808302860136819003810190615b98565b815260200190600101906149d3565b836001600160a01b03168d6001600160a01b031614614ad5576001600160a01b0384168787614a2f600182615bca565b818110614a3e57614a3e615bdd565b9050608002016020016020810190614a5691906156b2565b6001600160a01b031614614a7d576040516332b2410360e21b815260040160405180910390fd5b614ad58d8c8c60a001358a8a808060200260200160405190810160405280939291908181526020016000905b8282101561234457614ac660808302860136819003810190615b98565b81526020019060010190614aa9565b50505050505050505050505050565b6000614af360208301836156b2565b90506000614b0760408401602085016156b2565b90506000614b1b6060850160408601615c17565b90506000614b2f60808601606087016156b2565b90506000614b3f85858585611779565b6040516370a0823160e01b81523060048201529091506000908190614c329088908890889088906001600160a01b038516906370a0823190602401602060405180830381865afa158015614b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bbb9190615c34565b6040516370a0823160e01b81523060048201526001600160a01b038d16906370a0823190602401602060405180830381865afa158015614bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c239190615c34565b8e60c001358f60e00135614efc565b91509150614c41878484614747565b610ccd868483614747565b801580614cc65750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614ca0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cc49190615c34565b155b614d365760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084015b60405180910390fd5b6040516001600160a01b038316602482015260448101829052613cfd90849063095ea7b360e01b90606401613711565b6000614dbb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661500b9092919063ffffffff16565b805190915015613cfd5780806020019051810190614dd99190615c4d565b613cfd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401614d2d565b6040516001600160a01b038316602482015260448101829052613cfd90849063a9059cbb60e01b90606401613711565b600080608083901c15614e7d57608092831c92015b604083901c15614e8f57604092831c92015b602083901c15614ea157602092831c92015b601083901c15614eb357601092831c92015b600883901c15614ec557600892831c92015b600483901c15614ed757600492831c92015b600283901c15614ee957600292831c92015b600183901c156147415760010192915050565b60008083861015614f2057604051636e35977960e11b815260040160405180910390fd5b82851015614f415760405163acee051360e01b815260040160405180910390fd5b600080614f508c8c8c8c611de8565b91509150816000148015614f62575080155b15614f7257879350869250614ffc565b6000614f7f8984846146cc565b9050878111614fb45785811015614fa957604051630d32418960e21b815260040160405180910390fd5b889450925082614ffa565b6000614fc18984866146cc565b905089811115614fd357614fd3615c6a565b87811015614ff4576040516323d9bb0560e21b815260040160405180910390fd5b94508793505b505b50509850989650505050505050565b6060611c5f848460008585600080866001600160a01b031685876040516150329190615ed7565b60006040518083038185875af1925050503d806000811461506f576040519150601f19603f3d011682016040523d82523d6000602084013e615074565b606091505b509150915061508587838387615090565b979650505050505050565b606083156150ff5782516000036150f8576001600160a01b0385163b6150f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401614d2d565b5081611c5f565b611c5f83838151156151145781518083602001fd5b8060405162461bcd60e51b8152600401614d2d9190615f56565b6001600160a01b038116811461369657600080fd5b803561514e8161512e565b919050565b801515811461369657600080fd5b60008083601f84011261517357600080fd5b5081356001600160401b0381111561518a57600080fd5b6020830191508360208260071b850101111561124c57600080fd5b6000806000806000806000806000806101008b8d0312156151c557600080fd5b8a356151d08161512e565b995060208b01356151e08161512e565b985060408b01356151f081615153565b975060608b01356152008161512e565b965060808b0135955060a08b0135945060c08b01356001600160401b038082111561522a57600080fd5b6152368e838f01615161565b909650945060e08d013591508082111561524f57600080fd5b5061525c8d828e01615161565b915080935050809150509295989b9194979a5092959850565b600080600080600080600080610100898b03121561529257600080fd5b883561529d8161512e565b975060208901356152ad8161512e565b965060408901356152bd81615153565b9550606089013594506080890135935060a0890135925060c08901356152e28161512e565b8092505060e089013590509295985092959890939650565b60008060008060008060a0878903121561531357600080fd5b863595506020870135945060408701356001600160401b0381111561533757600080fd5b61534389828a01615161565b90955093505060608701356153578161512e565b80925050608087013590509295509295509295565b60008060008060006080868803121561538457600080fd5b8535945060208601356001600160401b038111156153a157600080fd5b6153ad88828901615161565b90955093505060408601356153c18161512e565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615410576154106153d2565b604052919050565b60006001600160401b03821115615431576154316153d2565b5060051b60200190565b60008060008060006080868803121561545357600080fd5b85356001600160401b038082111561546a57600080fd5b818801915088601f83011261547e57600080fd5b8135602061549361548e83615418565b6153e8565b82815260059290921b8401810191818101908c8411156154b257600080fd5b948201945b838610156154d0578535825294820194908201906154b7565b995050890135925050808211156154e657600080fd5b506154f388828901615161565b90955093506153c1905060408701615143565b6020808252825182820181905260009190848201906040850190845b8181101561553e57835183529284019291840191600101615522565b50909695505050505050565b6000806040838503121561555d57600080fd5b82356155688161512e565b915060208301356155788161512e565b809150509250929050565b60006080828403121561559557600080fd5b604051608081018181106001600160401b03821117156155b7576155b76153d2565b60405290508082356155c88161512e565b815260208301356155d88161512e565b602082015260408301356155eb81615153565b604082015260608301356155fe8161512e565b6060919091015292915050565b6000806040838503121561561e57600080fd5b823591506020808401356001600160401b0381111561563c57600080fd5b8401601f8101861361564d57600080fd5b803561565b61548e82615418565b81815260079190911b8201830190838101908883111561567a57600080fd5b928401925b828410156156a3576156918985615583565b8252848201915060808401935061567f565b80955050505050509250929050565b6000602082840312156156c457600080fd5b81356146c58161512e565b60008060008060008060008060006101208a8c0312156156ee57600080fd5b89356156f98161512e565b985060208a01356157098161512e565b975060408a013561571981615153565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356157458161512e565b809250506101008a013590509295985092959850929598565b600080600080600080600080600060e08a8c03121561577c57600080fd5b89356157878161512e565b985060208a01356157978161512e565b975060408a01356157a781615153565b965060608a01356157b78161512e565b955060808a0135945060a08a01356001600160401b03808211156157da57600080fd5b6157e68d838e01615161565b909650945060c08c01359150808211156157ff57600080fd5b5061580c8c828d01615161565b915080935050809150509295985092959850929598565b6000806000806080858703121561583957600080fd5b84356158448161512e565b935060208501356158548161512e565b9250604085013561586481615153565b915060608501356158748161512e565b939692955090935050565b6000610100828403121561589257600080fd5b50919050565b6000806000806000806000610180888a0312156158b457600080fd5b87356158bf8161512e565b9650602088013595506158d58960408a0161587f565b94506101408801356001600160401b03808211156158f257600080fd5b6158fe8b838c01615161565b90965094506101608a013591508082111561591857600080fd5b506159258a828b01615161565b989b979a50959850939692959293505050565b600080600080600080600060e0888a03121561595357600080fd5b873561595e8161512e565b9650602088013561596e81615153565b955060408801359450606088013593506080880135925060a08801356159938161512e565b8092505060c0880135905092959891949750929550565b600080600080600060a086880312156159c257600080fd5b85356159cd8161512e565b945060208601356159dd8161512e565b935060408601356159ed81615153565b925060608601356159fd8161512e565b949793965091946080013592915050565b60008060008060008060c08789031215615a2757600080fd5b8635615a328161512e565b95506020870135615a428161512e565b94506040870135615a5281615153565b93506060870135615a628161512e565b9598949750929560808101359460a0909101359350915050565b600080600060608486031215615a9157600080fd5b8335615a9c8161512e565b92506020840135615aac8161512e565b91506040840135615abc8161512e565b809150509250925092565b6000806000806000806000806000806101e08b8d031215615ae757600080fd5b8a35615af28161512e565b995060208b0135985060408b01359750615b0f8c60608d0161587f565b96506101608b01356001600160401b0380821115615b2c57600080fd5b615b388e838f01615161565b90985096506101808d0135915080821115615b5257600080fd5b50615b5f8d828e01615161565b9095509350506101a08b0135615b748161512e565b91506101c08b0135615b8581615153565b809150509295989b9194979a5092959850565b600060808284031215615baa57600080fd5b61473e8383615583565b634e487b7160e01b600052601160045260246000fd5b8181038181111561474157614741615bb4565b634e487b7160e01b600052603260045260246000fd5b60008060408385031215615c0657600080fd5b505080516020909101519092909150565b600060208284031215615c2957600080fd5b81356146c581615153565b600060208284031215615c4657600080fd5b5051919050565b600060208284031215615c5f57600080fd5b81516146c581615153565b634e487b7160e01b600052600160045260246000fd5b8082018082111561474157614741615bb4565b600060018201615ca557615ca5615bb4565b5060010190565b600060208284031215615cbe57600080fd5b81516146c58161512e565b6bffffffffffffffffffffffff19606094851b811682529290931b9091166014830152151560f81b602882015260290190565b600080600060608486031215615d1157600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152901515604082015260600190565b808202811582820484141761474157614741615bb4565b634e487b7160e01b600052601260045260246000fd5b600082615d9857634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615daf57600080fd5b815160ff811681146146c557600080fd5b600181815b80851115615dfb578160001904821115615de157615de1615bb4565b80851615615dee57918102915b93841c9390800290615dc5565b509250929050565b600082615e1257506001614741565b81615e1f57506000614741565b8160018114615e355760028114615e3f57615e5b565b6001915050614741565b60ff841115615e5057615e50615bb4565b50506001821b614741565b5060208310610133831016604e8410600b8410161715615e7e575081810a614741565b615e888383615dc0565b8060001904821115615e9c57615e9c615bb4565b029392505050565b600061473e60ff841683615e03565b60005b83811015615ece578181015183820152602001615eb6565b50506000910152565b60008251615ee9818460208701615eb3565b9190910192915050565b60008151808452615f0b816020860160208601615eb3565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b0383166040820152608060608201526000615f4c6080830184615ef3565b9695505050505050565b60208152600061473e6020830184615ef356fea2646970667358221220b1099ee7ddb5dc2ea1ec270042b192b9761fe430654308578bf270f4f8bb35cd64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000006824df38d1d77eadeb6bafcb03904e27429ab74000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b00000000000000000000000025cbddb98b35ab1ff77413456b31ec81a6b6b746000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c0000000000000000000000004200000000000000000000000000000000000006
-----Decoded View---------------
Arg [0] : _forwarder (address): 0x06824df38D1D77eADEB6baFCB03904E27429Ab74
Arg [1] : _factoryRegistry (address): 0xF4c67CdEAaB8360370F41514d06e32CcD8aA1d7B
Arg [2] : _v1Factory (address): 0x25CbdDb98b35ab1FF77413456B31EC81A6B6B746
Arg [3] : _factory (address): 0xF1046053aa5682b4F9a81b5481394DA16BE5FF5a
Arg [4] : _voter (address): 0x41C914ee0c7E1A5edCD0295623e6dC557B5aBf3C
Arg [5] : _weth (address): 0x4200000000000000000000000000000000000006
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000006824df38d1d77eadeb6bafcb03904e27429ab74
Arg [1] : 000000000000000000000000f4c67cdeaab8360370f41514d06e32ccd8aa1d7b
Arg [2] : 00000000000000000000000025cbddb98b35ab1ff77413456b31ec81a6b6b746
Arg [3] : 000000000000000000000000f1046053aa5682b4f9a81b5481394da16be5ff5a
Arg [4] : 00000000000000000000000041c914ee0c7e1a5edcd0295623e6dc557b5abf3c
Arg [5] : 0000000000000000000000004200000000000000000000000000000000000006
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 77.25% | $1,789.9 | 4.1566 | $7,439.84 | |
ARB | 8.83% | $1,790.2 | 0.4752 | $850.72 | |
BASE | 7.18% | $1,789.45 | 0.3867 | $691.9 | |
ZKSYNC | 3.82% | $1,788.39 | 0.2057 | $367.87 | |
LINEA | 1.82% | $1,788.39 | 0.098 | $175.26 | |
BSC | 1.09% | $614.64 | 0.1704 | $104.75 | |
OPBNB | <0.01% | $614.64 | 0.0002 | $0.122927 | |
POL | <0.01% | $0.220378 | 0.2635 | $0.058061 | |
MANTLE | <0.01% | $0.698325 | 0.0003 | $0.000209 |
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.