// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {BinHelper} from "./libraries/BinHelper.sol";
import {Constants} from "./libraries/Constants.sol";
import {Encoded} from "./libraries/math/Encoded.sol";
import {FeeHelper} from "./libraries/FeeHelper.sol";
import {JoeLibrary} from "./libraries/JoeLibrary.sol";
import {LiquidityConfigurations} from "./libraries/math/LiquidityConfigurations.sol";
import {PackedUint128Math} from "./libraries/math/PackedUint128Math.sol";
import {TokenHelper, IERC20} from "./libraries/TokenHelper.sol";
import {Uint256x256Math} from "./libraries/math/Uint256x256Math.sol";
import {IJoePair} from "./interfaces/IJoePair.sol";
import {ILBPair} from "./interfaces/ILBPair.sol";
import {ILBLegacyPair} from "./interfaces/ILBLegacyPair.sol";
import {ILBToken} from "./interfaces/ILBToken.sol";
import {ILBRouter} from "./interfaces/ILBRouter.sol";
import {ILBLegacyRouter} from "./interfaces/ILBLegacyRouter.sol";
import {IJoeFactory} from "./interfaces/IJoeFactory.sol";
import {ILBLegacyFactory} from "./interfaces/ILBLegacyFactory.sol";
import {ILBFactory} from "./interfaces/ILBFactory.sol";
import {IWNATIVE} from "./interfaces/IWNATIVE.sol";
/**
* @title Liquidity Book Router
* @author Trader Joe
* @notice Main contract to interact with to swap and manage liquidity on Joe V2 exchange.
*/
contract LBRouter is ILBRouter {
using TokenHelper for IERC20;
using JoeLibrary for uint256;
using PackedUint128Math for bytes32;
ILBFactory private immutable _factory2_2;
ILBFactory private immutable _factory2_1;
IJoeFactory private immutable _factoryV1;
ILBLegacyFactory private immutable _legacyFactory;
ILBLegacyRouter private immutable _legacyRouter;
IWNATIVE private immutable _wnative;
modifier onlyFactoryOwner() {
if (msg.sender != Ownable(address(_factory2_2)).owner()) revert LBRouter__NotFactoryOwner();
_;
}
modifier ensure(uint256 deadline) {
if (block.timestamp > deadline) revert LBRouter__DeadlineExceeded(deadline, block.timestamp);
_;
}
modifier verifyPathValidity(Path memory path) {
if (
path.pairBinSteps.length == 0 || path.versions.length != path.pairBinSteps.length
|| path.pairBinSteps.length + 1 != path.tokenPath.length
) revert LBRouter__LengthsMismatch();
_;
}
/**
* @notice Constructor
* @param factory2_2 Address of Joe V2.2 factory
* @param factory2_1 Address of Joe V2.1 factory
* @param factoryV1 Address of Joe V1 factory
* @param legacyFactory Address of Joe V2 factory
* @param legacyRouter Address of Joe V2 router
* @param wnative Address of WNATIVE
*/
constructor(
ILBFactory factory2_2,
IJoeFactory factoryV1,
ILBLegacyFactory legacyFactory,
ILBLegacyRouter legacyRouter,
ILBFactory factory2_1,
IWNATIVE wnative
) {
_factory2_2 = factory2_2;
_factory2_1 = factory2_1;
_factoryV1 = factoryV1;
_legacyFactory = legacyFactory;
_legacyRouter = legacyRouter;
_wnative = wnative;
}
/**
* @dev Receive function that only accept NATIVE from the WNATIVE contract
*/
receive() external payable {
if (msg.sender != address(_wnative)) revert LBRouter__SenderIsNotWNATIVE();
}
/**
* View function to get the factory V2.1 address
* @return lbFactory The address of the factory V2.1
*/
function getFactory() external view override returns (ILBFactory lbFactory) {
return _factory2_2;
}
/**
* View function to get the factory V2.1 address
* @return lbFactory The address of the factory V2.1
*/
function getFactoryV2_1() external view override returns (ILBFactory lbFactory) {
return _factory2_1;
}
/**
* View function to get the factory V2 address
* @return legacyLBfactory The address of the factory V2
*/
function getLegacyFactory() external view override returns (ILBLegacyFactory legacyLBfactory) {
return _legacyFactory;
}
/**
* View function to get the factory V1 address
* @return factoryV1 The address of the factory V1
*/
function getV1Factory() external view override returns (IJoeFactory factoryV1) {
return _factoryV1;
}
/**
* View function to get the router V2 address
* @return legacyRouter The address of the router V2
*/
function getLegacyRouter() external view override returns (ILBLegacyRouter legacyRouter) {
return _legacyRouter;
}
/**
* View function to get the WNATIVE address
* @return wnative The address of WNATIVE
*/
function getWNATIVE() external view override returns (IWNATIVE wnative) {
return _wnative;
}
/**
* @notice Returns the approximate id corresponding to the inputted price.
* Warning, the returned id may be inaccurate close to the start price of a bin
* @param pair The address of the LBPair
* @param price The price of y per x (multiplied by 1e36)
* @return The id corresponding to this price
*/
function getIdFromPrice(ILBPair pair, uint256 price) external view override returns (uint24) {
return pair.getIdFromPrice(price);
}
/**
* @notice Returns the price corresponding to the inputted id
* @param pair The address of the LBPair
* @param id The id
* @return The price corresponding to this id
*/
function getPriceFromId(ILBPair pair, uint24 id) external view override returns (uint256) {
return pair.getPriceFromId(id);
}
/**
* @notice Simulate a swap in
* @param pair The address of the LBPair
* @param amountOut The amount of token to receive
* @param swapForY Whether you swap X for Y (true), or Y for X (false)
* @return amountIn The amount of token to send in order to receive amountOut token
* @return amountOutLeft The amount of token Out that can't be returned due to a lack of liquidity
* @return fee The amount of fees paid in token sent
*/
function getSwapIn(ILBPair pair, uint128 amountOut, bool swapForY)
public
view
override
returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee)
{
(amountIn, amountOutLeft, fee) = pair.getSwapIn(amountOut, swapForY);
}
/**
* @notice Simulate a swap out
* @param pair The address of the LBPair
* @param amountIn The amount of token sent
* @param swapForY Whether you swap X for Y (true), or Y for X (false)
* @return amountInLeft The amount of token In that can't be swapped due to a lack of liquidity
* @return amountOut The amount of token received if amountIn tokenX are sent
* @return fee The amount of fees paid in token sent
*/
function getSwapOut(ILBPair pair, uint128 amountIn, bool swapForY)
external
view
override
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee)
{
(amountInLeft, amountOut, fee) = pair.getSwapOut(amountIn, swapForY);
}
/**
* @notice Create a liquidity bin LBPair for tokenX and tokenY using the factory
* @param tokenX The address of the first token
* @param tokenY The address of the second token
* @param activeId The active id of the pair
* @param binStep The bin step in basis point, used to calculate log(1 + binStep)
* @return pair The address of the newly created LBPair
*/
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
override
returns (ILBPair pair)
{
pair = _factory2_2.createLBPair(tokenX, tokenY, activeId, binStep);
}
/**
* @notice Add liquidity while performing safety checks
* @dev This function is compliant with fee on transfer tokens
* @param liquidityParameters The liquidity parameters
* @return amountXAdded The amount of token X added
* @return amountYAdded The amount of token Y added
* @return amountXLeft The amount of token X left (sent back to liquidityParameters.refundTo)
* @return amountYLeft The amount of token Y left (sent back to liquidityParameters.refundTo)
* @return depositIds The ids of the deposits
* @return liquidityMinted The amount of liquidity minted
*/
function addLiquidity(LiquidityParameters calldata liquidityParameters)
external
override
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
)
{
ILBPair lbPair = ILBPair(
_getLBPairInformation(
liquidityParameters.tokenX, liquidityParameters.tokenY, liquidityParameters.binStep, Version.V2_2
)
);
if (liquidityParameters.tokenX != lbPair.getTokenX()) revert LBRouter__WrongTokenOrder();
_safeTransferFrom(liquidityParameters.tokenX, msg.sender, address(lbPair), liquidityParameters.amountX);
_safeTransferFrom(liquidityParameters.tokenY, msg.sender, address(lbPair), liquidityParameters.amountY);
(amountXAdded, amountYAdded, amountXLeft, amountYLeft, depositIds, liquidityMinted) =
_addLiquidity(liquidityParameters, lbPair);
}
/**
* @notice Add liquidity with NATIVE while performing safety checks
* @dev This function is compliant with fee on transfer tokens
* @param liquidityParameters The liquidity parameters
* @return amountXAdded The amount of token X added
* @return amountYAdded The amount of token Y added
* @return amountXLeft The amount of token X left (sent back to liquidityParameters.refundTo)
* @return amountYLeft The amount of token Y left (sent back to liquidityParameters.refundTo)
* @return depositIds The ids of the deposits
* @return liquidityMinted The amount of liquidity minted
*/
function addLiquidityNATIVE(LiquidityParameters calldata liquidityParameters)
external
payable
override
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
)
{
ILBPair _LBPair = ILBPair(
_getLBPairInformation(
liquidityParameters.tokenX, liquidityParameters.tokenY, liquidityParameters.binStep, Version.V2_2
)
);
if (liquidityParameters.tokenX != _LBPair.getTokenX()) revert LBRouter__WrongTokenOrder();
if (liquidityParameters.tokenX == _wnative && liquidityParameters.amountX == msg.value) {
_safeTransferFrom(liquidityParameters.tokenY, msg.sender, address(_LBPair), liquidityParameters.amountY);
_wNativeDepositAndTransfer(address(_LBPair), msg.value);
} else if (liquidityParameters.tokenY == _wnative && liquidityParameters.amountY == msg.value) {
_safeTransferFrom(liquidityParameters.tokenX, msg.sender, address(_LBPair), liquidityParameters.amountX);
_wNativeDepositAndTransfer(address(_LBPair), msg.value);
} else {
revert LBRouter__WrongNativeLiquidityParameters(
address(liquidityParameters.tokenX),
address(liquidityParameters.tokenY),
liquidityParameters.amountX,
liquidityParameters.amountY,
msg.value
);
}
(amountXAdded, amountYAdded, amountXLeft, amountYLeft, depositIds, liquidityMinted) =
_addLiquidity(liquidityParameters, _LBPair);
}
/**
* @notice Remove liquidity while performing safety checks
* @dev This function is compliant with fee on transfer tokens
* @param tokenX The address of token X
* @param tokenY The address of token Y
* @param binStep The bin step of the LBPair
* @param amountXMin The min amount to receive of token X
* @param amountYMin The min amount to receive of token Y
* @param ids The list of ids to burn
* @param amounts The list of amounts to burn of each id in `_ids`
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountX Amount of token X returned
* @return amountY Amount of token Y returned
*/
function removeLiquidity(
IERC20 tokenX,
IERC20 tokenY,
uint16 binStep,
uint256 amountXMin,
uint256 amountYMin,
uint256[] memory ids,
uint256[] memory amounts,
address to,
uint256 deadline
) external override ensure(deadline) returns (uint256 amountX, uint256 amountY) {
ILBPair _LBPair = ILBPair(_getLBPairInformation(tokenX, tokenY, binStep, Version.V2_2));
bool isWrongOrder = tokenX != _LBPair.getTokenX();
if (isWrongOrder) (amountXMin, amountYMin) = (amountYMin, amountXMin);
(amountX, amountY) = _removeLiquidity(_LBPair, amountXMin, amountYMin, ids, amounts, to);
if (isWrongOrder) (amountX, amountY) = (amountY, amountX);
}
/**
* @notice Remove NATIVE liquidity while performing safety checks
* @dev This function is **NOT** compliant with fee on transfer tokens.
* This is wanted as it would make users pays the fee on transfer twice,
* use the `removeLiquidity` function to remove liquidity with fee on transfer tokens.
* @param token The address of token
* @param binStep The bin step of the LBPair
* @param amountTokenMin The min amount to receive of token
* @param amountNATIVEMin The min amount to receive of NATIVE
* @param ids The list of ids to burn
* @param amounts The list of amounts to burn of each id in `_ids`
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountToken Amount of token returned
* @return amountNATIVE Amount of NATIVE returned
*/
function removeLiquidityNATIVE(
IERC20 token,
uint16 binStep,
uint256 amountTokenMin,
uint256 amountNATIVEMin,
uint256[] memory ids,
uint256[] memory amounts,
address payable to,
uint256 deadline
) external override ensure(deadline) returns (uint256 amountToken, uint256 amountNATIVE) {
ILBPair lbPair = ILBPair(_getLBPairInformation(token, IERC20(_wnative), binStep, Version.V2_2));
{
bool isNATIVETokenY = IERC20(_wnative) == lbPair.getTokenY();
if (!isNATIVETokenY) {
(amountTokenMin, amountNATIVEMin) = (amountNATIVEMin, amountTokenMin);
}
(uint256 amountX, uint256 amountY) =
_removeLiquidity(lbPair, amountTokenMin, amountNATIVEMin, ids, amounts, address(this));
(amountToken, amountNATIVE) = isNATIVETokenY ? (amountX, amountY) : (amountY, amountX);
}
_safeTransfer(token, to, amountToken);
_wNativeWithdrawAndTransfer(to, amountNATIVE);
}
/**
* @notice Swaps exact tokens for tokens while performing safety checks
* @param amountIn The amount of token to send
* @param amountOutMin The min amount of token to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountIn);
amountOut = _swapExactTokensForTokens(amountIn, pairs, path.versions, path.tokenPath, to);
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
/**
* @notice Swaps exact tokens for NATIVE while performing safety checks
* @param amountIn The amount of token to send
* @param amountOutMinNATIVE The min amount of NATIVE to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactTokensForNATIVE(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountIn);
amountOut = _swapExactTokensForTokens(amountIn, pairs, path.versions, path.tokenPath, address(this));
if (amountOutMinNATIVE > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMinNATIVE, amountOut);
_wNativeWithdrawAndTransfer(to, amountOut);
}
/**
* @notice Swaps exact NATIVE for tokens while performing safety checks
* @param amountOutMin The min amount of token to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactNATIVEForTokens(uint256 amountOutMin, Path memory path, address to, uint256 deadline)
external
payable
override
ensure(deadline)
verifyPathValidity(path)
returns (uint256 amountOut)
{
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
_wNativeDepositAndTransfer(pairs[0], msg.value);
amountOut = _swapExactTokensForTokens(msg.value, pairs, path.versions, path.tokenPath, to);
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
/**
* @notice Swaps tokens for exact tokens while performing safety checks
* @param amountOut The amount of token to receive
* @param amountInMax The max amount of token to send
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountsIn Input amounts of the swap
*/
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256[] memory amountsIn) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
{
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountOut);
if (amountsIn[0] > amountInMax) revert LBRouter__MaxAmountInExceeded(amountInMax, amountsIn[0]);
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountsIn[0]);
uint256 _amountOutReal = _swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, to);
if (_amountOutReal < amountOut) revert LBRouter__InsufficientAmountOut(amountOut, _amountOutReal);
}
}
/**
* @notice Swaps tokens for exact NATIVE while performing safety checks
* @param amountNATIVEOut The amount of NATIVE to receive
* @param amountInMax The max amount of token to send
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountsIn path amounts for every step of the swap
*/
function swapTokensForExactNATIVE(
uint256 amountNATIVEOut,
uint256 amountInMax,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256[] memory amountsIn) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountNATIVEOut);
if (amountsIn[0] > amountInMax) revert LBRouter__MaxAmountInExceeded(amountInMax, amountsIn[0]);
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountsIn[0]);
uint256 _amountOutReal =
_swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, address(this));
if (_amountOutReal < amountNATIVEOut) revert LBRouter__InsufficientAmountOut(amountNATIVEOut, _amountOutReal);
_wNativeWithdrawAndTransfer(to, _amountOutReal);
}
/**
* @notice Swaps NATIVE for exact tokens while performing safety checks
* @dev Will refund any NATIVE amount sent in excess to `msg.sender`
* @param amountOut The amount of tokens to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountsIn path amounts for every step of the swap
*/
function swapNATIVEForExactTokens(uint256 amountOut, Path memory path, address to, uint256 deadline)
external
payable
override
ensure(deadline)
verifyPathValidity(path)
returns (uint256[] memory amountsIn)
{
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountOut);
if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);
_wNativeDepositAndTransfer(pairs[0], amountsIn[0]);
uint256 amountOutReal = _swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, to);
if (amountOutReal < amountOut) revert LBRouter__InsufficientAmountOut(amountOut, amountOutReal);
if (msg.value > amountsIn[0]) _safeTransferNative(msg.sender, msg.value - amountsIn[0]);
}
/**
* @notice Swaps exact tokens for tokens while performing safety checks supporting for fee on transfer tokens
* @param amountIn The amount of token to send
* @param amountOutMin The min amount of token to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
IERC20 targetToken = path.tokenPath[pairs.length];
uint256 balanceBefore = targetToken.balanceOf(to);
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountIn);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, to);
amountOut = targetToken.balanceOf(to) - balanceBefore;
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
/**
* @notice Swaps exact tokens for NATIVE while performing safety checks supporting for fee on transfer tokens
* @param amountIn The amount of token to send
* @param amountOutMinNATIVE The min amount of NATIVE to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactTokensForNATIVESupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
uint256 balanceBefore = _wnative.balanceOf(address(this));
_safeTransferFrom(path.tokenPath[0], msg.sender, pairs[0], amountIn);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, address(this));
amountOut = _wnative.balanceOf(address(this)) - balanceBefore;
if (amountOutMinNATIVE > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMinNATIVE, amountOut);
_wNativeWithdrawAndTransfer(to, amountOut);
}
/**
* @notice Swaps exact NATIVE for tokens while performing safety checks supporting for fee on transfer tokens
* @param amountOutMin The min amount of token to receive
* @param path The path of the swap
* @param to The address of the recipient
* @param deadline The deadline of the tx
* @return amountOut Output amount of the swap
*/
function swapExactNATIVEForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external payable override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
IERC20 targetToken = path.tokenPath[pairs.length];
uint256 balanceBefore = targetToken.balanceOf(to);
_wNativeDepositAndTransfer(pairs[0], msg.value);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, to);
amountOut = targetToken.balanceOf(to) - balanceBefore;
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
/**
* @notice Unstuck tokens that are sent to this contract by mistake
* @dev Only callable by the factory owner
* @param token The address of the token
* @param to The address of the user to send back the tokens
* @param amount The amount to send
*/
function sweep(IERC20 token, address to, uint256 amount) external override onlyFactoryOwner {
if (address(token) == address(0)) {
amount = amount == type(uint256).max ? address(this).balance : amount;
_safeTransferNative(to, amount);
} else {
amount = amount == type(uint256).max ? token.balanceOf(address(this)) : amount;
token.safeTransfer(to, amount);
}
}
/**
* @notice Unstuck LBTokens that are sent to this contract by mistake
* @dev Only callable by the factory owner
* @param lbToken The address of the LBToken
* @param to The address of the user to send back the tokens
* @param ids The list of token ids
* @param amounts The list of amounts to send
*/
function sweepLBToken(ILBToken lbToken, address to, uint256[] calldata ids, uint256[] calldata amounts)
external
override
onlyFactoryOwner
{
lbToken.batchTransferFrom(address(this), to, ids, amounts);
}
/**
* @notice Helper function to add liquidity
* @param liq The liquidity parameter
* @param pair LBPair where liquidity is deposited
* @return amountXAdded Amount of token X added
* @return amountYAdded Amount of token Y added
* @return amountXLeft Amount of token X left
* @return amountYLeft Amount of token Y left
* @return depositIds The list of deposit ids
* @return liquidityMinted The list of liquidity minted
*/
function _addLiquidity(LiquidityParameters calldata liq, ILBPair pair)
private
ensure(liq.deadline)
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
)
{
unchecked {
if (liq.deltaIds.length != liq.distributionX.length || liq.deltaIds.length != liq.distributionY.length) {
revert LBRouter__LengthsMismatch();
}
if (liq.activeIdDesired > type(uint24).max || liq.idSlippage > type(uint24).max) {
revert LBRouter__IdDesiredOverflows(liq.activeIdDesired, liq.idSlippage);
}
bytes32[] memory liquidityConfigs = new bytes32[](liq.deltaIds.length);
depositIds = new uint256[](liq.deltaIds.length);
{
uint256 _activeId = pair.getActiveId();
if (
liq.activeIdDesired + liq.idSlippage < _activeId || _activeId + liq.idSlippage < liq.activeIdDesired
) {
revert LBRouter__IdSlippageCaught(liq.activeIdDesired, liq.idSlippage, _activeId);
}
for (uint256 i; i < liquidityConfigs.length; ++i) {
int256 _id = int256(_activeId) + liq.deltaIds[i];
if (_id < 0 || uint256(_id) > type(uint24).max) revert LBRouter__IdOverflows(_id);
depositIds[i] = uint256(_id);
liquidityConfigs[i] = LiquidityConfigurations.encodeParams(
uint64(liq.distributionX[i]), uint64(liq.distributionY[i]), uint24(uint256(_id))
);
}
}
bytes32 amountsReceived;
bytes32 amountsLeft;
(amountsReceived, amountsLeft, liquidityMinted) = pair.mint(liq.to, liquidityConfigs, liq.refundTo);
bytes32 amountsAdded = amountsReceived.sub(amountsLeft);
amountXAdded = amountsAdded.decodeX();
amountYAdded = amountsAdded.decodeY();
if (amountXAdded < liq.amountXMin || amountYAdded < liq.amountYMin) {
revert LBRouter__AmountSlippageCaught(liq.amountXMin, amountXAdded, liq.amountYMin, amountYAdded);
}
amountXLeft = amountsLeft.decodeX();
amountYLeft = amountsLeft.decodeY();
}
}
/**
* @notice Helper function to return the amounts in
* @param versions The list of versions (V1, V2, V2_1 or V2_2)
* @param pairs The list of pairs
* @param tokenPath The swap path
* @param amountOut The amount out
* @return amountsIn The list of amounts in
*/
function _getAmountsIn(
Version[] memory versions,
address[] memory pairs,
IERC20[] memory tokenPath,
uint256 amountOut
) private view returns (uint256[] memory amountsIn) {
amountsIn = new uint256[](tokenPath.length);
// Avoid doing -1, as `pairs.length == pairBinSteps.length-1`
amountsIn[pairs.length] = amountOut;
for (uint256 i = pairs.length; i != 0; i--) {
IERC20 token = tokenPath[i - 1];
Version version = versions[i - 1];
address pair = pairs[i - 1];
if (version == Version.V1) {
(uint256 reserveIn, uint256 reserveOut,) = IJoePair(pair).getReserves();
if (token > tokenPath[i]) {
(reserveIn, reserveOut) = (reserveOut, reserveIn);
}
uint256 amountOut_ = amountsIn[i];
amountsIn[i - 1] = uint128(amountOut_.getAmountIn(reserveIn, reserveOut));
} else if (version == Version.V2) {
(amountsIn[i - 1],) = _legacyRouter.getSwapIn(
ILBLegacyPair(pair), uint128(amountsIn[i]), ILBLegacyPair(pair).tokenX() == token
);
} else {
(amountsIn[i - 1],,) =
getSwapIn(ILBPair(pair), uint128(amountsIn[i]), ILBPair(pair).getTokenX() == token);
}
}
}
/**
* @notice Helper function to remove liquidity
* @param pair The address of the LBPair
* @param amountXMin The min amount to receive of token X
* @param amountYMin The min amount to receive of token Y
* @param ids The list of ids to burn
* @param amounts The list of amounts to burn of each id in `_ids`
* @param to The address of the recipient
* @return amountX The amount of token X sent by the pair
* @return amountY The amount of token Y sent by the pair
*/
function _removeLiquidity(
ILBPair pair,
uint256 amountXMin,
uint256 amountYMin,
uint256[] memory ids,
uint256[] memory amounts,
address to
) private returns (uint256 amountX, uint256 amountY) {
(bytes32[] memory amountsBurned) = pair.burn(msg.sender, to, ids, amounts);
for (uint256 i; i < amountsBurned.length; ++i) {
amountX += amountsBurned[i].decodeX();
amountY += amountsBurned[i].decodeY();
}
if (amountX < amountXMin || amountY < amountYMin) {
revert LBRouter__AmountSlippageCaught(amountXMin, amountX, amountYMin, amountY);
}
}
/**
* @notice Helper function to swap exact tokens for tokens
* @param amountIn The amount of token sent
* @param pairs The list of pairs
* @param versions The list of versions (V1, V2, V2_1 or V2_2)
* @param tokenPath The swap path using the binSteps following `pairBinSteps`
* @param to The address of the recipient
* @return amountOut The amount of token sent to `to`
*/
function _swapExactTokensForTokens(
uint256 amountIn,
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
address to
) private returns (uint256 amountOut) {
IERC20 token;
Version version;
address recipient;
address pair;
IERC20 tokenNext = tokenPath[0];
amountOut = amountIn;
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
(uint256 reserve0, uint256 reserve1,) = IJoePair(pair).getReserves();
if (token < tokenNext) {
amountOut = amountOut.getAmountOut(reserve0, reserve1);
IJoePair(pair).swap(0, amountOut, recipient, "");
} else {
amountOut = amountOut.getAmountOut(reserve1, reserve0);
IJoePair(pair).swap(amountOut, 0, recipient, "");
}
} else if (version == Version.V2) {
bool swapForY = tokenNext == ILBLegacyPair(pair).tokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBLegacyPair(pair).swap(swapForY, recipient);
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
} else {
bool swapForY = tokenNext == ILBPair(pair).getTokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBPair(pair).swap(swapForY, recipient).decode();
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
}
}
}
}
/**
* @notice Helper function to swap tokens for exact tokens
* @param pairs The array of pairs
* @param versions The list of versions (V1, V2, V2_1 or V2_2)
* @param tokenPath The swap path using the binSteps following `pairBinSteps`
* @param amountsIn The list of amounts in
* @param to The address of the recipient
* @return amountOut The amount of token sent to `to`
*/
function _swapTokensForExactTokens(
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
uint256[] memory amountsIn,
address to
) private returns (uint256 amountOut) {
IERC20 token;
address recipient;
address pair;
Version version;
IERC20 tokenNext = tokenPath[0];
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
amountOut = amountsIn[i + 1];
if (token < tokenNext) {
IJoePair(pair).swap(0, amountOut, recipient, "");
} else {
IJoePair(pair).swap(amountOut, 0, recipient, "");
}
} else if (version == Version.V2) {
bool swapForY = tokenNext == ILBLegacyPair(pair).tokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBLegacyPair(pair).swap(swapForY, recipient);
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
} else {
bool swapForY = tokenNext == ILBPair(pair).getTokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBPair(pair).swap(swapForY, recipient).decode();
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
}
}
}
}
/**
* @notice Helper function to swap exact tokens supporting for fee on transfer tokens
* @param pairs The list of pairs
* @param versions The list of versions (V1, V2, V2_1 or V2_2)
* @param tokenPath The swap path using the binSteps following `pairBinSteps`
* @param to The address of the recipient
*/
function _swapSupportingFeeOnTransferTokens(
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
address to
) private {
IERC20 token;
Version version;
address recipient;
address pair;
IERC20 tokenNext = tokenPath[0];
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
(uint256 _reserve0, uint256 _reserve1,) = IJoePair(pair).getReserves();
if (token < tokenNext) {
uint256 amountIn = token.balanceOf(pair) - _reserve0;
uint256 amountOut = amountIn.getAmountOut(_reserve0, _reserve1);
IJoePair(pair).swap(0, amountOut, recipient, "");
} else {
uint256 amountIn = token.balanceOf(pair) - _reserve1;
uint256 amountOut = amountIn.getAmountOut(_reserve1, _reserve0);
IJoePair(pair).swap(amountOut, 0, recipient, "");
}
} else if (version == Version.V2) {
ILBLegacyPair(pair).swap(tokenNext == ILBLegacyPair(pair).tokenY(), recipient);
} else {
ILBPair(pair).swap(tokenNext == ILBPair(pair).getTokenY(), recipient);
}
}
}
}
/**
* @notice Helper function to return the address of the LBPair
* @dev Revert if the pair is not created yet
* @param tokenX The address of the tokenX
* @param tokenY The address of the tokenY
* @param binStep The bin step of the LBPair
* @param version The version of the LBPair
* @return lbPair The address of the LBPair
*/
function _getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep, Version version)
private
view
returns (address lbPair)
{
if (version == Version.V2) {
lbPair = address(_legacyFactory.getLBPairInformation(tokenX, tokenY, binStep).LBPair);
} else if (version == Version.V2_1) {
lbPair = address(_factory2_1.getLBPairInformation(tokenX, tokenY, binStep).LBPair);
} else {
lbPair = address(_factory2_2.getLBPairInformation(tokenX, tokenY, binStep).LBPair);
}
if (lbPair == address(0)) {
revert LBRouter__PairNotCreated(address(tokenX), address(tokenY), binStep);
}
}
/**
* @notice Helper function to return the address of the pair (v1 or v2, according to `binStep`)
* @dev Revert if the pair is not created yet
* @param tokenX The address of the tokenX
* @param tokenY The address of the tokenY
* @param binStep The bin step of the LBPair
* @param version The version of the LBPair
* @return pair The address of the pair of binStep `binStep`
*/
function _getPair(IERC20 tokenX, IERC20 tokenY, uint256 binStep, Version version)
private
view
returns (address pair)
{
if (version == Version.V1) {
pair = _factoryV1.getPair(address(tokenX), address(tokenY));
if (pair == address(0)) revert LBRouter__PairNotCreated(address(tokenX), address(tokenY), binStep);
} else {
pair = address(_getLBPairInformation(tokenX, tokenY, binStep, version));
}
}
/**
* @notice Helper function to return a list of pairs
* @param pairBinSteps The list of bin steps
* @param versions The list of versions (V1, V2, V2_1 or V2_2)
* @param tokenPath The swap path using the binSteps following `pairBinSteps`
* @return pairs The list of pairs
*/
function _getPairs(uint256[] memory pairBinSteps, Version[] memory versions, IERC20[] memory tokenPath)
private
view
returns (address[] memory pairs)
{
pairs = new address[](pairBinSteps.length);
IERC20 token;
IERC20 tokenNext = tokenPath[0];
unchecked {
for (uint256 i; i < pairs.length; ++i) {
token = tokenNext;
tokenNext = tokenPath[i + 1];
pairs[i] = _getPair(token, tokenNext, pairBinSteps[i], versions[i]);
}
}
}
/**
* @notice Helper function to transfer tokens to `to`
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount to send
*/
function _safeTransfer(IERC20 token, address to, uint256 amount) private {
if (amount == 0) return;
token.safeTransfer(to, amount);
}
/**
* @notice Helper function to transfer tokens from `from` to `to`
* @param token The address of the token
* @param from The address of the sender
* @param to The address of the recipient
* @param amount The amount to send
*/
function _safeTransferFrom(IERC20 token, address from, address to, uint256 amount) private {
if (amount == 0) return;
token.safeTransferFrom(from, to, amount);
}
/**
* @notice Helper function to transfer NATIVE to `to`
* @param to The address of the recipient
* @param amount The amount to send
*/
function _safeTransferNative(address to, uint256 amount) private {
if (amount == 0) return;
(bool success,) = to.call{value: amount}("");
if (!success) revert LBRouter__FailedToSendNATIVE(to, amount);
}
/**
* @notice Helper function to deposit and transfer WNative to `to`
* @param to The address of the recipient
* @param amount The amount to deposit and transfer
*/
function _wNativeDepositAndTransfer(address to, uint256 amount) private {
if (amount == 0) return;
_wnative.deposit{value: amount}();
IERC20(_wnative).safeTransfer(to, amount);
}
/**
* @notice Helper function to withdraw and transfer WNative to `to`
* @param to The address of the recipient
* @param amount The amount to withdraw and transfer
*/
function _wNativeWithdrawAndTransfer(address to, uint256 amount) private {
if (amount == 0) return;
_wnative.withdraw(amount);
_safeTransferNative(to, amount);
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "factory2_2",
"type": "address",
"internalType": "contract ILBFactory"
},
{
"name": "factoryV1",
"type": "address",
"internalType": "contract IJoeFactory"
},
{
"name": "legacyFactory",
"type": "address",
"internalType": "contract ILBLegacyFactory"
},
{
"name": "legacyRouter",
"type": "address",
"internalType": "contract ILBLegacyRouter"
},
{
"name": "factory2_1",
"type": "address",
"internalType": "contract ILBFactory"
},
{
"name": "wnative",
"type": "address",
"internalType": "contract IWNATIVE"
}
],
"stateMutability": "nonpayable"
},
{
"name": "JoeLibrary__InsufficientAmount",
"type": "error",
"inputs": []
},
{
"name": "JoeLibrary__InsufficientLiquidity",
"type": "error",
"inputs": []
},
{
"name": "LBRouter__AmountSlippageBPTooBig",
"type": "error",
"inputs": [
{
"name": "amountSlippage",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__AmountSlippageCaught",
"type": "error",
"inputs": [
{
"name": "amountXMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountX",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountY",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__BinReserveOverflows",
"type": "error",
"inputs": [
{
"name": "id",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__BrokenSwapSafetyCheck",
"type": "error",
"inputs": []
},
{
"name": "LBRouter__DeadlineExceeded",
"type": "error",
"inputs": [
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "currentTimestamp",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__FailedToSendNATIVE",
"type": "error",
"inputs": [
{
"name": "recipient",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__IdDesiredOverflows",
"type": "error",
"inputs": [
{
"name": "idDesired",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "idSlippage",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__IdOverflows",
"type": "error",
"inputs": [
{
"name": "id",
"type": "int256",
"internalType": "int256"
}
]
},
{
"name": "LBRouter__IdSlippageCaught",
"type": "error",
"inputs": [
{
"name": "activeIdDesired",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "idSlippage",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "activeId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__InsufficientAmountOut",
"type": "error",
"inputs": [
{
"name": "amountOutMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__InvalidTokenPath",
"type": "error",
"inputs": [
{
"name": "wrongToken",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "LBRouter__InvalidVersion",
"type": "error",
"inputs": [
{
"name": "version",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__LengthsMismatch",
"type": "error",
"inputs": []
},
{
"name": "LBRouter__MaxAmountInExceeded",
"type": "error",
"inputs": [
{
"name": "amountInMax",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountIn",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__NotFactoryOwner",
"type": "error",
"inputs": []
},
{
"name": "LBRouter__PairNotCreated",
"type": "error",
"inputs": [
{
"name": "tokenX",
"type": "address",
"internalType": "address"
},
{
"name": "tokenY",
"type": "address",
"internalType": "address"
},
{
"name": "binStep",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__SenderIsNotWNATIVE",
"type": "error",
"inputs": []
},
{
"name": "LBRouter__SwapOverflows",
"type": "error",
"inputs": [
{
"name": "id",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__TooMuchTokensIn",
"type": "error",
"inputs": [
{
"name": "excess",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__WrongAmounts",
"type": "error",
"inputs": [
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "reserve",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__WrongNativeLiquidityParameters",
"type": "error",
"inputs": [
{
"name": "tokenX",
"type": "address",
"internalType": "address"
},
{
"name": "tokenY",
"type": "address",
"internalType": "address"
},
{
"name": "amountX",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountY",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "msgValue",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"name": "LBRouter__WrongTokenOrder",
"type": "error",
"inputs": []
},
{
"name": "PackedUint128Math__SubUnderflow",
"type": "error",
"inputs": []
},
{
"name": "TokenHelper__TransferFailed",
"type": "error",
"inputs": []
},
{
"name": "addLiquidity",
"type": "function",
"inputs": [
{
"name": "liquidityParameters",
"type": "tuple",
"components": [
{
"name": "tokenX",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "tokenY",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "binStep",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountX",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountY",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountXMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "activeIdDesired",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "idSlippage",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "deltaIds",
"type": "int256[]",
"internalType": "int256[]"
},
{
"name": "distributionX",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "distributionY",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "refundTo",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"internalType": "struct ILBRouter.LiquidityParameters"
}
],
"outputs": [
{
"name": "amountXAdded",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYAdded",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountXLeft",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYLeft",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "depositIds",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "liquidityMinted",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "nonpayable"
},
{
"name": "addLiquidityNATIVE",
"type": "function",
"inputs": [
{
"name": "liquidityParameters",
"type": "tuple",
"components": [
{
"name": "tokenX",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "tokenY",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "binStep",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountX",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountY",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountXMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "activeIdDesired",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "idSlippage",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "deltaIds",
"type": "int256[]",
"internalType": "int256[]"
},
{
"name": "distributionX",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "distributionY",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "refundTo",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"internalType": "struct ILBRouter.LiquidityParameters"
}
],
"outputs": [
{
"name": "amountXAdded",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYAdded",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountXLeft",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYLeft",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "depositIds",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "liquidityMinted",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "payable"
},
{
"name": "createLBPair",
"type": "function",
"inputs": [
{
"name": "tokenX",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "tokenY",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "activeId",
"type": "uint24",
"internalType": "uint24"
},
{
"name": "binStep",
"type": "uint16",
"internalType": "uint16"
}
],
"outputs": [
{
"name": "pair",
"type": "address",
"internalType": "contract ILBPair"
}
],
"stateMutability": "nonpayable"
},
{
"name": "getFactory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "lbFactory",
"type": "address",
"internalType": "contract ILBFactory"
}
],
"stateMutability": "view"
},
{
"name": "getFactoryV2_1",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "lbFactory",
"type": "address",
"internalType": "contract ILBFactory"
}
],
"stateMutability": "view"
},
{
"name": "getIdFromPrice",
"type": "function",
"inputs": [
{
"name": "pair",
"type": "address",
"internalType": "contract ILBPair"
},
{
"name": "price",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "uint24",
"internalType": "uint24"
}
],
"stateMutability": "view"
},
{
"name": "getLegacyFactory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "legacyLBfactory",
"type": "address",
"internalType": "contract ILBLegacyFactory"
}
],
"stateMutability": "view"
},
{
"name": "getLegacyRouter",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "legacyRouter",
"type": "address",
"internalType": "contract ILBLegacyRouter"
}
],
"stateMutability": "view"
},
{
"name": "getPriceFromId",
"type": "function",
"inputs": [
{
"name": "pair",
"type": "address",
"internalType": "contract ILBPair"
},
{
"name": "id",
"type": "uint24",
"internalType": "uint24"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "getSwapIn",
"type": "function",
"inputs": [
{
"name": "pair",
"type": "address",
"internalType": "contract ILBPair"
},
{
"name": "amountOut",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "swapForY",
"type": "bool",
"internalType": "bool"
}
],
"outputs": [
{
"name": "amountIn",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "amountOutLeft",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "fee",
"type": "uint128",
"internalType": "uint128"
}
],
"stateMutability": "view"
},
{
"name": "getSwapOut",
"type": "function",
"inputs": [
{
"name": "pair",
"type": "address",
"internalType": "contract ILBPair"
},
{
"name": "amountIn",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "swapForY",
"type": "bool",
"internalType": "bool"
}
],
"outputs": [
{
"name": "amountInLeft",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "amountOut",
"type": "uint128",
"internalType": "uint128"
},
{
"name": "fee",
"type": "uint128",
"internalType": "uint128"
}
],
"stateMutability": "view"
},
{
"name": "getV1Factory",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "factoryV1",
"type": "address",
"internalType": "contract IJoeFactory"
}
],
"stateMutability": "view"
},
{
"name": "getWNATIVE",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "wnative",
"type": "address",
"internalType": "contract IWNATIVE"
}
],
"stateMutability": "view"
},
{
"name": "removeLiquidity",
"type": "function",
"inputs": [
{
"name": "tokenX",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "tokenY",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "binStep",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "amountXMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountYMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "ids",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "amounts",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountX",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountY",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "removeLiquidityNATIVE",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "binStep",
"type": "uint16",
"internalType": "uint16"
},
{
"name": "amountTokenMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountNATIVEMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "ids",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "amounts",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "to",
"type": "address",
"internalType": "address payable"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountToken",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountNATIVE",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapExactNATIVEForTokens",
"type": "function",
"inputs": [
{
"name": "amountOutMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "payable"
},
{
"name": "swapExactNATIVEForTokensSupportingFeeOnTransferTokens",
"type": "function",
"inputs": [
{
"name": "amountOutMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "payable"
},
{
"name": "swapExactTokensForNATIVE",
"type": "function",
"inputs": [
{
"name": "amountIn",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountOutMinNATIVE",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address payable"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapExactTokensForNATIVESupportingFeeOnTransferTokens",
"type": "function",
"inputs": [
{
"name": "amountIn",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountOutMinNATIVE",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address payable"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapExactTokensForTokens",
"type": "function",
"inputs": [
{
"name": "amountIn",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountOutMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapExactTokensForTokensSupportingFeeOnTransferTokens",
"type": "function",
"inputs": [
{
"name": "amountIn",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountOutMin",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapNATIVEForExactTokens",
"type": "function",
"inputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountsIn",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "payable"
},
{
"name": "swapTokensForExactNATIVE",
"type": "function",
"inputs": [
{
"name": "amountNATIVEOut",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountInMax",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address payable"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountsIn",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "nonpayable"
},
{
"name": "swapTokensForExactTokens",
"type": "function",
"inputs": [
{
"name": "amountOut",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amountInMax",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "path",
"type": "tuple",
"components": [
{
"name": "pairBinSteps",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "versions",
"type": "uint8[]",
"internalType": "enum ILBRouter.Version[]"
},
{
"name": "tokenPath",
"type": "address[]",
"internalType": "contract IERC20[]"
}
],
"internalType": "struct ILBRouter.Path"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "amountsIn",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "nonpayable"
},
{
"name": "sweep",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "contract IERC20"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "sweepLBToken",
"type": "function",
"inputs": [
{
"name": "lbToken",
"type": "address",
"internalType": "contract ILBToken"
},
{
"name": "to",
"type": "address",
"internalType": "address"
},
{
"name": "ids",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "amounts",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "receive",
"stateMutability": "payable"
}
]0x6101406040523480156200001257600080fd5b50604051620053b9380380620053b983398101604081905262000035916200007f565b6001600160a01b0395861660805290851660a05292841660c05290831660e052821661010052166101205262000113565b6001600160a01b03811681146200007c57600080fd5b50565b60008060008060008060c087890312156200009957600080fd5b8651620000a68162000066565b6020880151909650620000b98162000066565b6040880151909550620000cc8162000066565b6060880151909450620000df8162000066565b6080880151909350620000f28162000066565b60a0880151909250620001058162000066565b809150509295509295509295565b60805160a05160c05160e05161010051610120516151ae6200020b600039600081816101b5015281816103430152818161069801528181610776015281816108520152818161099501528181610d220152818161133e015281816113da01528181611541015281816115c40152818161190701528181611b9c01528181611e85015281816128c501528181612de40152612e620152600081816105130152612b85015260008181610376015261389001526000818161054601526140ce0152600081816102bc015261394e0152600081816103de015281816110e3015281816112900152818161207f01526139ab01526151ae6000f3fe6080604052600436106101a55760003560e01c806392fe8e70116100e1578063ba8465231161008a578063d0e380f211610064578063d0e380f21461058a578063e038e6dc146105aa578063e9361c08146105bd578063f96fe925146105dd57600080fd5b8063ba84652314610504578063bb558a9f14610537578063c22159b61461056a57600080fd5b8063a0d376cf116100bb578063a0d376cf146104b1578063a3c7271a146104d1578063b066ea7c146104f157600080fd5b806392fe8e7014610427578063964f987c146104475780639ab6156b1461049157600080fd5b806362c067671161014e57806371d1974a1161012857806371d1974a1461036757806381c2fdfb1461039a57806388cc58e4146103cf5780638efc2b2c1461040257600080fd5b806362c06767146102f4578063659ac74b146103145780636c9c00781461033457600080fd5b80633dc8f8ec1161017f5780633dc8f8ec1461026d5780634b8018701461028d5780635c5035cb146102ad57600080fd5b80631a24f9a9146101fa5780632075ad221461022d5780632a443fae1461024d57600080fd5b366101f557336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101f357604051636c8cb79360e01b815260040160405180910390fd5b005b600080fd5b34801561020657600080fd5b5061021a6102153660046146c4565b610611565b6040519081526020015b60405180910390f35b61024061023b36600461472f565b610913565b60405161022491906147cb565b34801561025957600080fd5b5061021a6102683660046146c4565b610b73565b34801561027957600080fd5b506102406102883660046146c4565b610ca0565b34801561029957600080fd5b5061021a6102a83660046146c4565b610ea6565b3480156102b957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610224565b34801561030057600080fd5b506101f361030f3660046147de565b6110e1565b34801561032057600080fd5b506102dc61032f36600461484b565b611251565b34801561034057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b34801561037357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b3480156103a657600080fd5b506103ba6103b53660046148a7565b611308565b60408051928352602083019190915201610224565b3480156103db57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b610415610410366004614962565b611461565b604051610224969594939291906149a5565b34801561043357600080fd5b506102406104423660046146c4565b6116b0565b34801561045357600080fd5b50610467610462366004614a12565b6117f5565b604080516001600160801b0394851681529284166020840152921691810191909152606001610224565b34801561049d57600080fd5b5061021a6104ac3660046146c4565b611885565b3480156104bd57600080fd5b506104676104cc366004614a12565b6119f9565b3480156104dd57600080fd5b506104156104ec366004614962565b611a3d565b61021a6104ff36600461472f565b611b1a565b34801561051057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b34801561054357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b34801561057657600080fd5b506103ba610585366004614a5d565b611c94565b34801561059657600080fd5b5061021a6105a5366004614b25565b611d8a565b61021a6105b836600461472f565b611e03565b3480156105c957600080fd5b506101f36105d8366004614baa565b61207d565b3480156105e957600080fd5b506105fd6105f8366004614c3f565b6121a0565b60405162ffffff9091168152602001610224565b600081804211156106435760405163dae7ca7d60e01b8152600481018290524260248201526044015b60405180910390fd5b8451518590158061065b575080515160208201515114155b806106785750604081015151815151610675906001614c81565b14155b156106965760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168660400151876000015151815181106106db576106db614c94565b60200260200101516001600160a01b03161461073a5760408601518651518151811061070957610709614c94565b602002602001015160405163cfec0e0160e01b815260040161063a91906001600160a01b0391909116815260200190565b600061075387600001518860200151896040015161220c565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156107bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e19190614caa565b905061082788604001516000815181106107fd576107fd614c94565b6020026020010151338460008151811061081957610819614c94565b60200260200101518d61231c565b61083b8289602001518a604001513061233d565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156108a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c59190614caa565b6108cf9190614cc3565b9450848911156108fc576040516313fab00360e21b8152600481018a90526024810186905260440161063a565b61090687866128a3565b5050505095945050505050565b606081804211156109405760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610958575080515160208201515114155b806109755750604081015151815151610972906001614c81565b14155b156109935760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686604001516000815181106109d4576109d4614c94565b60200260200101516001600160a01b031614610a0157856040015160008151811061070957610709614c94565b6000610a1a87600001518860200151896040015161220c565b9050610a3087602001518289604001518b612937565b93503484600081518110610a4657610a46614c94565b60200260200101511115610a94573484600081518110610a6857610a68614c94565b602002602001015160405163194ee21960e31b815260040161063a929190918252602082015260400190565b610ad281600081518110610aaa57610aaa614c94565b602002602001015185600081518110610ac557610ac5614c94565b6020026020010151612dd6565b6000610ae98289602001518a60400151888b612e8d565b905088811015610b16576040516313fab00360e21b8152600481018a90526024810182905260440161063a565b84600081518110610b2957610b29614c94565b6020026020010151341115610b6757610b673386600081518110610b4f57610b4f614c94565b602002602001015134610b629190614cc3565b6132c6565b50505050949350505050565b60008180421115610ba05760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610bb8575080515160208201515114155b80610bd55750604081015151815151610bd2906001614c81565b14155b15610bf35760405163b91b4d4d60e01b815260040160405180910390fd5b6000610c0c87600001518860200151896040015161220c565b9050610c528760400151600081518110610c2857610c28614c94565b60200260200101513383600081518110610c4457610c44614c94565b60200260200101518c61231c565b610c67898289602001518a604001518a613358565b935083881115610c94576040516313fab00360e21b8152600481018990526024810185905260440161063a565b50505095945050505050565b60608180421115610ccd5760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610ce5575080515160208201515114155b80610d025750604081015151815151610cff906001614c81565b14155b15610d205760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866040015187600001515181518110610d6557610d65614c94565b60200260200101516001600160a01b031614610d935760408601518651518151811061070957610709614c94565b6000610dac87600001518860200151896040015161220c565b9050610dc287602001518289604001518c612937565b93508784600081518110610dd857610dd8614c94565b60200260200101511115610dfa578784600081518110610a6857610a68614c94565b610e588760400151600081518110610e1457610e14614c94565b60200260200101513383600081518110610e3057610e30614c94565b602002602001015187600081518110610e4b57610e4b614c94565b602002602001015161231c565b6000610e6f8289602001518a604001518830612e8d565b905089811015610e9c576040516313fab00360e21b8152600481018b90526024810182905260440161063a565b61090687826128a3565b60008180421115610ed35760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610eeb575080515160208201515114155b80610f085750604081015151815151610f05906001614c81565b14155b15610f265760405163b91b4d4d60e01b815260040160405180910390fd5b6000610f3f87600001518860200151896040015161220c565b905060008760400151825181518110610f5a57610f5a614c94565b60209081029190910101516040516370a0823160e01b81526001600160a01b0389811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610fb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd59190614caa565b905061101b8960400151600081518110610ff157610ff1614c94565b6020026020010151338560008151811061100d5761100d614c94565b60200260200101518e61231c565b61102f838a602001518b604001518b61233d565b6040516370a0823160e01b81526001600160a01b0389811660048301528291908416906370a0823190602401602060405180830381865afa158015611078573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109c9190614caa565b6110a69190614cc3565b9550858a11156110d3576040516313fab00360e21b8152600481018b90526024810187905260440161063a565b505050505095945050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111639190614cd6565b6001600160a01b0316336001600160a01b03161461119457604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b0383166111c45760001981146111b157806111b3565b475b90506111bf82826132c6565b505050565b60001981146111d3578061123b565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190614caa565b90506111bf6001600160a01b03841683836137e1565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063659ac74b906084016020604051808303816000875af11580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190614cd6565b95945050505050565b60008082804211156113365760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b60006113698c7f00000000000000000000000000000000000000000000000000000000000000008d61ffff166003613847565b90506000816001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190614cd6565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161490508061140e579899985b60008061141f848e8e8e8e30613a66565b915091508261142f578082611432565b81815b80975081985050505050506114488c8786613bc8565b61145286846128a3565b50509850989650505050505050565b60008080806060808261149661147a60208a018a614cf3565b61148a60408b0160208c01614cf3565b8a604001356003613847565b9050806001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fa9190614cd6565b6001600160a01b031661151060208a018a614cf3565b6001600160a01b0316146115375760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661156e60208a018a614cf3565b6001600160a01b03161480156115875750348860600135145b156115ba576115ab61159f60408a0160208b01614cf3565b33838b6080013561231c565b6115b58134612dd6565b611691565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166115f460408a0160208b01614cf3565b6001600160a01b031614801561160d5750348860800135145b1561162e576115ab61162260208a018a614cf3565b33838b6060013561231c565b61163b6020890189614cf3565b61164b60408a0160208b01614cf3565b60405163d0a4f13b60e01b81526001600160a01b03928316600482015291166024820152606089013560448201526080890135606482015234608482015260a40161063a565b61169b8882613be9565b949d939c50919a509850965090945092505050565b606081804211156116dd5760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b845151859015806116f5575080515160208201515114155b80611712575060408101515181515161170f906001614c81565b14155b156117305760405163b91b4d4d60e01b815260040160405180910390fd5b600061174987600001518860200151896040015161220c565b905061175f87602001518289604001518c612937565b9350878460008151811061177557611775614c94565b60200260200101511115611797578784600081518110610a6857610a68614c94565b6117b18760400151600081518110610e1457610e14614c94565b60006117c88289602001518a60400151888b612e8d565b905089811015610906576040516313fab00360e21b8152600481018b90526024810182905260440161063a565b604051630abcd78360e41b81526001600160801b03831660048201528115156024820152600090819081906001600160a01b0387169063abcd7830906044015b606060405180830381865afa158015611852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118769190614d10565b91989097509095509350505050565b600081804211156118b25760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b845151859015806118ca575080515160208201515114155b806118e757506040810151518151516118e4906001614c81565b14155b156119055760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686604001518760000151518151811061194a5761194a614c94565b60200260200101516001600160a01b0316146119785760408601518651518151811061070957610709614c94565b600061199187600001518860200151896040015161220c565b90506119ad8760400151600081518110610c2857610c28614c94565b6119c2898289602001518a6040015130613358565b9350838811156119ef576040516313fab00360e21b8152600481018990526024810185905260440161063a565b610c9486856128a3565b604051631cee6cdf60e31b81526001600160801b03831660048201528115156024820152600090819081906001600160a01b0387169063e77366f890604401611835565b600080808060608082611a5661147a60208a018a614cf3565b9050806001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190614cd6565b6001600160a01b0316611ad060208a018a614cf3565b6001600160a01b031614611af75760405163b33f8ab960e01b815260040160405180910390fd5b611b0761162260208a018a614cf3565b61169161159f60408a0160208b01614cf3565b60008180421115611b475760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580611b5f575080515160208201515114155b80611b7c5750604081015151815151611b79906001614c81565b14155b15611b9a5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168660400151600081518110611bdb57611bdb614c94565b60200260200101516001600160a01b031614611c0857856040015160008151811061070957610709614c94565b6000611c2187600001518860200151896040015161220c565b9050611c4781600081518110611c3957611c39614c94565b602002602001015134612dd6565b611c5c348289602001518a604001518a613358565b935083881115611c89576040516313fab00360e21b8152600481018990526024810185905260440161063a565b505050949350505050565b6000808280421115611cc25760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b6000611cd58d8d8d61ffff166003613847565b90506000816001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614cd6565b6001600160a01b03168e6001600160a01b0316141590508015611d5c579899985b611d6a828c8c8c8c8c613a66565b90955093508015611d79579293925b505050995099975050505050505050565b604051634c7cffbd60e01b815262ffffff821660048201526000906001600160a01b03841690634c7cffbd90602401602060405180830381865afa158015611dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfa9190614caa565b90505b92915050565b60008180421115611e305760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580611e48575080515160208201515114155b80611e655750604081015151815151611e62906001614c81565b14155b15611e835760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168660400151600081518110611ec457611ec4614c94565b60200260200101516001600160a01b031614611ef157856040015160008151811061070957610709614c94565b6000611f0a87600001518860200151896040015161220c565b905060008760400151825181518110611f2557611f25614c94565b60209081029190910101516040516370a0823160e01b81526001600160a01b0389811660048301529192506000918316906370a0823190602401602060405180830381865afa158015611f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa09190614caa565b9050611fb883600081518110611c3957611c39614c94565b611fcc838a602001518b604001518b61233d565b6040516370a0823160e01b81526001600160a01b0389811660048301528291908416906370a0823190602401602060405180830381865afa158015612015573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120399190614caa565b6120439190614cc3565b9550858a1115612070576040516313fab00360e21b8152600481018b90526024810187905260440161063a565b5050505050949350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ff9190614cd6565b6001600160a01b0316336001600160a01b03161461213057604051635d9515b960e11b815260040160405180910390fd5b6040516305feb5ff60e21b81526001600160a01b038716906317fad7fc9061216690309089908990899089908990600401614d9d565b600060405180830381600087803b15801561218057600080fd5b505af1158015612194573d6000803e3d6000fd5b50505050505050505050565b60405163f5e2932960e01b8152600481018290526000906001600160a01b0384169063f5e2932990602401602060405180830381865afa1580156121e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfa9190614ddd565b6060835167ffffffffffffffff8111156122285761222861441f565b604051908082528060200260200182016040528015612251578160200160208202803683370190505b5090506000808360008151811061226a5761226a614c94565b6020026020010151905060005b83518110156123125781925084816001018151811061229857612298614c94565b602002602001015191506122e083838984815181106122b9576122b9614c94565b60200260200101518985815181106122d3576122d3614c94565b602002602001015161408d565b8482815181106122f2576122f2614c94565b6001600160a01b0390921660209283029190910190910152600101612277565b5050509392505050565b8015612337576123376001600160a01b03851684848461418d565b50505050565b60008060008060008660008151811061235857612358614c94565b6020026020010151905060005b89518110156121945789818151811061238057612380614c94565b6020026020010151925088818151811061239c5761239c614c94565b602002602001015194508195508781600101815181106123be576123be614c94565b60200260200101519150895181600101146123f5578981600101815181106123e8576123e8614c94565b60200260200101516123f7565b865b9350600085600381111561240d5761240d614dfa565b036126b357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124779190614e27565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b031610156125ac576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa1580156124f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125179190614caa565b0390506000612527828585614202565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b15801561258d57600080fd5b505af11580156125a1573d6000803e3d6000fd5b5050505050506126ac565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa1580156125f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261b9190614caa565b039050600061262b828486614202565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b15801561269157600080fd5b505af11580156126a5573d6000803e3d6000fd5b5050505050505b505061289b565b60018560038111156126c7576126c7614dfa565b036127b257826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190614cd6565b60405160e083901b6001600160e01b03191681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af115801561278e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ac9190614e6c565b826001600160a01b03166353c059a0846001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128239190614cd6565b60405160e083901b6001600160e01b03191681526001600160a01b0391821686831614600482015290871660248201526044016020604051808303816000875af1158015612875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128999190614caa565b505b600101612365565b806000036128af575050565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561291157600080fd5b505af1158015612925573d6000803e3d6000fd5b5050505061293382826132c6565b5050565b6060825167ffffffffffffffff8111156129535761295361441f565b60405190808252806020026020018201604052801561297c578160200160208202803683370190505b509050818185518151811061299357612993614c94565b602090810291909101015283515b8015612dcd576000846129b5600184614cc3565b815181106129c5576129c5614c94565b602002602001015190506000876001846129df9190614cc3565b815181106129ef576129ef614c94565b60200260200101519050600087600185612a099190614cc3565b81518110612a1957612a19614c94565b6020026020010151905060006003811115612a3657612a36614dfa565b826003811115612a4857612a48614dfa565b03612b6a57600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab29190614e27565b506001600160701b031691506001600160701b03169150888681518110612adb57612adb614c94565b60200260200101516001600160a01b0316856001600160a01b03161115612afe57905b6000878781518110612b1257612b12614c94565b60200260200101519050612b3183838361429c9092919063ffffffff16565b6001600160801b031688612b4660018a614cc3565b81518110612b5657612b56614c94565b602002602001018181525050505050612db7565b6001826003811115612b7e57612b7e614dfa565b03612cea577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635bdd4b7c82878781518110612bc557612bc5614c94565b6020026020010151866001600160a01b0316856001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c399190614cd6565b6040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526001600160801b0390931660248401529092169190911460448201526064016040805180830381865afa158015612c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbc9190614e6c565b5085612cc9600187614cc3565b81518110612cd957612cd9614c94565b602002602001018181525050612db7565b612d8381868681518110612d0057612d00614c94565b6020026020010151856001600160a01b0316846001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d749190614cd6565b6001600160a01b0316146117f5565b50506001600160801b031685612d9a600187614cc3565b81518110612daa57612daa614c94565b6020026020010181815250505b5050508080612dc590614e90565b9150506129a1565b50949350505050565b80600003612de2575050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612e3d57600080fd5b505af1158015612e51573d6000803e3d6000fd5b506129339350506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169150849050836137e1565b60008060008060008088600081518110612ea957612ea9614c94565b6020026020010151905060005b8b518110156132b7578b8181518110612ed157612ed1614c94565b602002602001015193508a8181518110612eed57612eed614c94565b60200260200101519250819550898160010181518110612f0f57612f0f614c94565b602002602001015191508b518160010114612f46578b8160010181518110612f3957612f39614c94565b6020026020010151612f48565b875b94506000836003811115612f5e57612f5e614dfa565b0361306957888160010181518110612f7857612f78614c94565b60200260200101519650816001600160a01b0316866001600160a01b0316101561301c5760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03878116604484015260806064840152608483019190915285169063022c0d9f9060a4015b600060405180830381600087803b158015612fff57600080fd5b505af1158015613013573d6000803e3d6000fd5b505050506132af565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03878116604484015260806064840152608483019190915285169063022c0d9f9060a401612fe5565b600183600381111561307d5761307d614dfa565b03613185576000846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e69190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052888316602483015292506000918291908816906353c059a09060440160408051808303816000875af1158015613143573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131679190614e6c565b9150915082156131795780995061317d565b8199505b5050506132af565b6000846001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156131c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e99190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052888316602483015292506000918291613283918916906353c059a0906044015b6020604051808303816000875af115801561324b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326f9190614caa565b6001600160801b0381169160809190911c90565b6001600160801b031691506001600160801b0316915082156132a7578099506132ab565b8199505b5050505b600101612eb6565b50505050505095945050505050565b806000036132d2575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461331f576040519150601f19603f3d011682016040523d82523d6000602084013e613324565b606091505b50509050806111bf5760405163047b96f760e41b81526001600160a01b03841660048201526024810183905260440161063a565b6000806000806000808760008151811061337457613374614c94565b602002602001015190508a955060005b8a518110156132b7578a818151811061339f5761339f614c94565b602002602001015192508981815181106133bb576133bb614c94565b602002602001015194508195508881600101815181106133dd576133dd614c94565b602002602001015191508a518160010114613414578a816001018151811061340757613407614c94565b6020026020010151613416565b875b9350600085600381111561342c5761342c614dfa565b036135e657600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134969190614e27565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613555576134d2898383614202565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561353857600080fd5b505af115801561354c573d6000803e3d6000fd5b505050506135df565b613560898284614202565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156135c657600080fd5b505af11580156135da573d6000803e3d6000fd5b505050505b50506137d9565b60018560038111156135fa576135fa614dfa565b03613702576000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561363f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136639190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af11580156136c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e49190614e6c565b9150915082156136f6578099506136fa565b8199505b5050506137d9565b6000836001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613742573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137669190614cd6565b60405163029e02cd60e51b81526001600160a01b0391821685831614600482018190528783166024830152925060009182916137ad918816906353c059a09060440161322c565b6001600160801b031691506001600160801b0316915082156137d1578099506137d5565b8199505b5050505b600101613384565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b179052612337848261433b565b6000600182600381111561385d5761385d614dfa565b036139075760405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063704037bd906064015b608060405180830381865afa1580156138d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fc9190614ea7565b602001519050613a1d565b600282600381111561391b5761391b614dfa565b0361397d5760405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063704037bd906064016138bb565b60405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063704037bd90606401608060405180830381865afa1580156139f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a169190614ea7565b6020015190505b6001600160a01b038116613a5e57604051636b2471d160e11b81526001600160a01b038087166004830152851660248201526044810184905260640161063a565b949350505050565b6000806000886001600160a01b031663c9939f5e338689896040518563ffffffff1660e01b8152600401613a9d9493929190614f0e565b6000604051808303816000875af1158015613abc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ae49190810190614f4c565b905060005b8151811015613b7857613b1b828281518110613b0757613b07614c94565b60200260200101516001600160801b031690565b613b2e906001600160801b031685614c81565b9350613b53828281518110613b4557613b45614c94565b602002602001015160801c90565b613b66906001600160801b031684614c81565b9250613b7181614fd2565b9050613ae9565b5087831080613b8657508682105b15613bbc576040516318ccfb7760e11b81526004810189905260248101849052604481018890526064810183905260840161063a565b50965096945050505050565b80600003613bd557505050565b6111bf6001600160a01b03841683836137e1565b600080600080606080876101c0013580421115613c225760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b613c306101408a018a614feb565b9050613c406101208b018b614feb565b9050141580613c6d5750613c586101608a018a614feb565b9050613c686101208b018b614feb565b905014155b15613c8b5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08a01351180613ca7575062ffffff6101008a0135115b15613cd65760405163197a55c760e11b815260e08a013560048201526101008a0135602482015260440161063a565b6000613ce66101208b018b614feb565b905067ffffffffffffffff811115613d0057613d0061441f565b604051908082528060200260200182016040528015613d29578160200160208202803683370190505b509050613d3a6101208b018b614feb565b905067ffffffffffffffff811115613d5457613d5461441f565b604051908082528060200260200182016040528015613d7d578160200160208202803683370190505b5093506000896001600160a01b031663dbe65edc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de49190614ddd565b62ffffff169050808b61010001358c60e00135011080613e0e57508a60e001358b61010001358201105b15613e4457604051637d50edab60e11b815260e08c013560048201526101008c013560248201526044810182905260640161063a565b60005b8251811015613f47576000613e606101208e018e614feb565b83818110613e7057613e70614c94565b90506020020135830190506000811280613e8c575062ffffff81115b15613ead576040516370a82e6160e11b81526004810182905260240161063a565b80878381518110613ec057613ec0614c94565b6020908102919091010152613f21613edc6101408f018f614feb565b84818110613eec57613eec614c94565b905060200201358e806101600190613f049190614feb565b85818110613f1457613f14614c94565b90506020020135836143ab565b848381518110613f3357613f33614c94565b602090810291909101015250600101613e47565b50506000808a6001600160a01b031663383d15c58d610180016020810190613f6f9190614cf3565b858f6101a0016020810190613f849190614cf3565b6040518463ffffffff1660e01b8152600401613fa293929190615035565b6000604051808303816000875af1158015613fc1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613fe99190810190615099565b965090925090506000613ffc83836143e5565b6001600160801b0381169b50608081901c9a50905060a08d01358b108061402657508c60c001358a105b15614062576040516318ccfb7760e11b815260a08e01356004820152602481018c905260c08e01356044820152606481018b905260840161063a565b6001600160801b0382169850608082901c6001600160801b0316975050505050509295509295509295565b6000808260038111156140a2576140a2614dfa565b036141815760405163e6a4390560e01b81526001600160a01b03868116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e6a4390590604401602060405180830381865afa158015614115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141399190614cd6565b90506001600160a01b03811661417c57604051636b2471d160e11b81526001600160a01b038087166004830152851660248201526044810184905260640161063a565b613a5e565b6112ff85858585613847565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b1790526141fb858261433b565b5050505050565b6000836000036142255760405163b229ed3360e01b815260040160405180910390fd5b821580614230575081155b1561424e576040516398c59a2960e01b815260040160405180910390fd5b600061425c856103e561513f565b9050600061426a848361513f565b905060008261427b876103e861513f565b6142859190614c81565b90506142918183615156565b979650505050505050565b6000836000036142bf5760405163b229ed3360e01b815260040160405180910390fd5b8215806142ca575081155b156142e8576040516398c59a2960e01b815260040160405180910390fd5b60006142f4858561513f565b614300906103e861513f565b9050600061430e8685614cc3565b61431a906103e561513f565b90506143268183615156565b614331906001614c81565b9695505050505050565b600080600052602060008351602085016000875af1905080801561437c573d801561436f5760016000511483169250614376565b843b151592505b5061438c565b3d1561438c573d6000803e3d6000fd5b50806111bf5760405163197138bd60e11b815260040160405180910390fd5b601882901b6affffffffffffffff00000016605884901b72ffffffffffffffff0000000000000000000000161762ffffff82168117613a5e565b8082038281118061440157506001600160801b03808416908216115b15611dfd5760405163e599af5560e01b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156144585761445861441f565b60405290565b6040516080810167ffffffffffffffff811182821017156144585761445861441f565b604051601f8201601f1916810167ffffffffffffffff811182821017156144aa576144aa61441f565b604052919050565b600067ffffffffffffffff8211156144cc576144cc61441f565b5060051b60200190565b600082601f8301126144e757600080fd5b813560206144fc6144f7836144b2565b614481565b82815260059290921b8401810191818101908684111561451b57600080fd5b8286015b84811015614536578035835291830191830161451f565b509695505050505050565b6001600160a01b038116811461455657600080fd5b50565b803561456481614541565b919050565b600082601f83011261457a57600080fd5b8135602061458a6144f7836144b2565b82815260059290921b840181019181810190868411156145a957600080fd5b8286015b848110156145365780356145c081614541565b83529183019183016145ad565b6000606082840312156145df57600080fd5b6145e7614435565b9050813567ffffffffffffffff8082111561460157600080fd5b61460d858386016144d6565b835260209150818401358181111561462457600080fd5b8401601f8101861361463557600080fd5b80356146436144f7826144b2565b81815260059190911b8201840190848101908883111561466257600080fd5b928501925b8284101561468e5783356004811061467f5760008081fd5b82529285019290850190614667565b80868801525050505060408401359150808211156146ab57600080fd5b506146b884828501614569565b60408301525092915050565b600080600080600060a086880312156146dc57600080fd5b8535945060208601359350604086013567ffffffffffffffff81111561470157600080fd5b61470d888289016145cd565b935050606086013561471e81614541565b949793965091946080013592915050565b6000806000806080858703121561474557600080fd5b84359350602085013567ffffffffffffffff81111561476357600080fd5b61476f878288016145cd565b935050604085013561478081614541565b9396929550929360600135925050565b600081518084526020808501945080840160005b838110156147c0578151875295820195908201906001016147a4565b509495945050505050565b602081526000611dfa6020830184614790565b6000806000606084860312156147f357600080fd5b83356147fe81614541565b9250602084013561480e81614541565b929592945050506040919091013590565b62ffffff8116811461455657600080fd5b61ffff8116811461455657600080fd5b803561456481614830565b6000806000806080858703121561486157600080fd5b843561486c81614541565b9350602085013561487c81614541565b9250604085013561488c8161481f565b9150606085013561489c81614830565b939692955090935050565b600080600080600080600080610100898b0312156148c457600080fd5b88356148cf81614541565b975060208901356148df81614830565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561490a57600080fd5b6149168c838d016144d6565b955060a08b013591508082111561492c57600080fd5b506149398b828c016144d6565b93505060c089013561494a81614541565b8092505060e089013590509295985092959890939650565b60006020828403121561497457600080fd5b813567ffffffffffffffff81111561498b57600080fd5b82016101e0818503121561499e57600080fd5b9392505050565b86815285602082015284604082015283606082015260c0608082015260006149d060c0830185614790565b82810360a08401526149e28185614790565b9998505050505050505050565b6001600160801b038116811461455657600080fd5b801515811461455657600080fd5b600080600060608486031215614a2757600080fd5b8335614a3281614541565b92506020840135614a42816149ef565b91506040840135614a5281614a04565b809150509250925092565b60008060008060008060008060006101208a8c031215614a7c57600080fd5b8935614a8781614541565b985060208a0135614a9781614541565b9750614aa560408b01614840565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff80821115614ad057600080fd5b614adc8d838e016144d6565b955060c08c0135915080821115614af257600080fd5b50614aff8c828d016144d6565b935050614b0e60e08b01614559565b91506101008a013590509295985092959850929598565b60008060408385031215614b3857600080fd5b8235614b4381614541565b91506020830135614b538161481f565b809150509250929050565b60008083601f840112614b7057600080fd5b50813567ffffffffffffffff811115614b8857600080fd5b6020830191508360208260051b8501011115614ba357600080fd5b9250929050565b60008060008060008060808789031215614bc357600080fd5b8635614bce81614541565b95506020870135614bde81614541565b9450604087013567ffffffffffffffff80821115614bfb57600080fd5b614c078a838b01614b5e565b90965094506060890135915080821115614c2057600080fd5b50614c2d89828a01614b5e565b979a9699509497509295939492505050565b60008060408385031215614c5257600080fd5b8235614c5d81614541565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dfd57611dfd614c6b565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614cbc57600080fd5b5051919050565b81810381811115611dfd57611dfd614c6b565b600060208284031215614ce857600080fd5b815161499e81614541565b600060208284031215614d0557600080fd5b813561499e81614541565b600080600060608486031215614d2557600080fd5b8351614d30816149ef565b6020850151909350614d41816149ef565b6040850151909250614a52816149ef565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614d8457600080fd5b8260051b80836020870137939093016020019392505050565b60006001600160a01b03808916835280881660208401525060806040830152614dca608083018688614d52565b82810360608401526149e2818587614d52565b600060208284031215614def57600080fd5b815161499e8161481f565b634e487b7160e01b600052602160045260246000fd5b80516001600160701b038116811461456457600080fd5b600080600060608486031215614e3c57600080fd5b614e4584614e10565b9250614e5360208501614e10565b9150604084015163ffffffff81168114614a5257600080fd5b60008060408385031215614e7f57600080fd5b505080516020909101519092909150565b600081614e9f57614e9f614c6b565b506000190190565b600060808284031215614eb957600080fd5b614ec161445e565b8251614ecc81614830565b81526020830151614edc81614541565b60208201526040830151614eef81614a04565b60408201526060830151614f0281614a04565b60608201529392505050565b60006001600160a01b03808716835280861660208401525060806040830152614f3a6080830185614790565b82810360608401526142918185614790565b60006020808385031215614f5f57600080fd5b825167ffffffffffffffff811115614f7657600080fd5b8301601f81018513614f8757600080fd5b8051614f956144f7826144b2565b81815260059190911b82018301908381019087831115614fb457600080fd5b928401925b8284101561429157835182529284019290840190614fb9565b600060018201614fe457614fe4614c6b565b5060010190565b6000808335601e1984360301811261500257600080fd5b83018035915067ffffffffffffffff82111561501d57600080fd5b6020019150600581901b3603821315614ba357600080fd5b6000606082016001600160a01b0380871684526020606081860152828751808552608087019150828901945060005b8181101561508057855183529483019491830191600101615064565b5050809450505080851660408501525050949350505050565b6000806000606084860312156150ae57600080fd5b835192506020808501519250604085015167ffffffffffffffff8111156150d457600080fd5b8501601f810187136150e557600080fd5b80516150f36144f7826144b2565b81815260059190911b8201830190838101908983111561511257600080fd5b928401925b8284101561513057835182529284019290840190615117565b80955050505050509250925092565b8082028115828204841417611dfd57611dfd614c6b565b60008261517357634e487b7160e01b600052601260045260246000fd5b50049056fea264697066735822122086d27368cbc63b44b36322b62f96bb4f9fb949db443e6d2465bc5b838863f03464736f6c63430008140033000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad73
0x6080604052600436106101a55760003560e01c806392fe8e70116100e1578063ba8465231161008a578063d0e380f211610064578063d0e380f21461058a578063e038e6dc146105aa578063e9361c08146105bd578063f96fe925146105dd57600080fd5b8063ba84652314610504578063bb558a9f14610537578063c22159b61461056a57600080fd5b8063a0d376cf116100bb578063a0d376cf146104b1578063a3c7271a146104d1578063b066ea7c146104f157600080fd5b806392fe8e7014610427578063964f987c146104475780639ab6156b1461049157600080fd5b806362c067671161014e57806371d1974a1161012857806371d1974a1461036757806381c2fdfb1461039a57806388cc58e4146103cf5780638efc2b2c1461040257600080fd5b806362c06767146102f4578063659ac74b146103145780636c9c00781461033457600080fd5b80633dc8f8ec1161017f5780633dc8f8ec1461026d5780634b8018701461028d5780635c5035cb146102ad57600080fd5b80631a24f9a9146101fa5780632075ad221461022d5780632a443fae1461024d57600080fd5b366101f557336001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad7316146101f357604051636c8cb79360e01b815260040160405180910390fd5b005b600080fd5b34801561020657600080fd5b5061021a6102153660046146c4565b610611565b6040519081526020015b60405180910390f35b61024061023b36600461472f565b610913565b60405161022491906147cb565b34801561025957600080fd5b5061021a6102683660046146c4565b610b73565b34801561027957600080fd5b506102406102883660046146c4565b610ca0565b34801561029957600080fd5b5061021a6102a83660046146c4565b610ea6565b3480156102b957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610224565b34801561030057600080fd5b506101f361030f3660046147de565b6110e1565b34801561032057600080fd5b506102dc61032f36600461484b565b611251565b34801561034057600080fd5b507f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736102dc565b34801561037357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b3480156103a657600080fd5b506103ba6103b53660046148a7565b611308565b60408051928352602083019190915201610224565b3480156103db57600080fd5b507f000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e6102dc565b610415610410366004614962565b611461565b604051610224969594939291906149a5565b34801561043357600080fd5b506102406104423660046146c4565b6116b0565b34801561045357600080fd5b50610467610462366004614a12565b6117f5565b604080516001600160801b0394851681529284166020840152921691810191909152606001610224565b34801561049d57600080fd5b5061021a6104ac3660046146c4565b611885565b3480156104bd57600080fd5b506104676104cc366004614a12565b6119f9565b3480156104dd57600080fd5b506104156104ec366004614962565b611a3d565b61021a6104ff36600461472f565b611b1a565b34801561051057600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b34801561054357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102dc565b34801561057657600080fd5b506103ba610585366004614a5d565b611c94565b34801561059657600080fd5b5061021a6105a5366004614b25565b611d8a565b61021a6105b836600461472f565b611e03565b3480156105c957600080fd5b506101f36105d8366004614baa565b61207d565b3480156105e957600080fd5b506105fd6105f8366004614c3f565b6121a0565b60405162ffffff9091168152602001610224565b600081804211156106435760405163dae7ca7d60e01b8152600481018290524260248201526044015b60405180910390fd5b8451518590158061065b575080515160208201515114155b806106785750604081015151815151610675906001614c81565b14155b156106965760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b03168660400151876000015151815181106106db576106db614c94565b60200260200101516001600160a01b03161461073a5760408601518651518151811061070957610709614c94565b602002602001015160405163cfec0e0160e01b815260040161063a91906001600160a01b0391909116815260200190565b600061075387600001518860200151896040015161220c565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad7316906370a0823190602401602060405180830381865afa1580156107bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e19190614caa565b905061082788604001516000815181106107fd576107fd614c94565b6020026020010151338460008151811061081957610819614c94565b60200260200101518d61231c565b61083b8289602001518a604001513061233d565b6040516370a0823160e01b815230600482015281907f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b0316906370a0823190602401602060405180830381865afa1580156108a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c59190614caa565b6108cf9190614cc3565b9450848911156108fc576040516313fab00360e21b8152600481018a90526024810186905260440161063a565b61090687866128a3565b5050505095945050505050565b606081804211156109405760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610958575080515160208201515114155b806109755750604081015151815151610972906001614c81565b14155b156109935760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b031686604001516000815181106109d4576109d4614c94565b60200260200101516001600160a01b031614610a0157856040015160008151811061070957610709614c94565b6000610a1a87600001518860200151896040015161220c565b9050610a3087602001518289604001518b612937565b93503484600081518110610a4657610a46614c94565b60200260200101511115610a94573484600081518110610a6857610a68614c94565b602002602001015160405163194ee21960e31b815260040161063a929190918252602082015260400190565b610ad281600081518110610aaa57610aaa614c94565b602002602001015185600081518110610ac557610ac5614c94565b6020026020010151612dd6565b6000610ae98289602001518a60400151888b612e8d565b905088811015610b16576040516313fab00360e21b8152600481018a90526024810182905260440161063a565b84600081518110610b2957610b29614c94565b6020026020010151341115610b6757610b673386600081518110610b4f57610b4f614c94565b602002602001015134610b629190614cc3565b6132c6565b50505050949350505050565b60008180421115610ba05760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610bb8575080515160208201515114155b80610bd55750604081015151815151610bd2906001614c81565b14155b15610bf35760405163b91b4d4d60e01b815260040160405180910390fd5b6000610c0c87600001518860200151896040015161220c565b9050610c528760400151600081518110610c2857610c28614c94565b60200260200101513383600081518110610c4457610c44614c94565b60200260200101518c61231c565b610c67898289602001518a604001518a613358565b935083881115610c94576040516313fab00360e21b8152600481018990526024810185905260440161063a565b50505095945050505050565b60608180421115610ccd5760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610ce5575080515160208201515114155b80610d025750604081015151815151610cff906001614c81565b14155b15610d205760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b0316866040015187600001515181518110610d6557610d65614c94565b60200260200101516001600160a01b031614610d935760408601518651518151811061070957610709614c94565b6000610dac87600001518860200151896040015161220c565b9050610dc287602001518289604001518c612937565b93508784600081518110610dd857610dd8614c94565b60200260200101511115610dfa578784600081518110610a6857610a68614c94565b610e588760400151600081518110610e1457610e14614c94565b60200260200101513383600081518110610e3057610e30614c94565b602002602001015187600081518110610e4b57610e4b614c94565b602002602001015161231c565b6000610e6f8289602001518a604001518830612e8d565b905089811015610e9c576040516313fab00360e21b8152600481018b90526024810182905260440161063a565b61090687826128a3565b60008180421115610ed35760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580610eeb575080515160208201515114155b80610f085750604081015151815151610f05906001614c81565b14155b15610f265760405163b91b4d4d60e01b815260040160405180910390fd5b6000610f3f87600001518860200151896040015161220c565b905060008760400151825181518110610f5a57610f5a614c94565b60209081029190910101516040516370a0823160e01b81526001600160a01b0389811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610fb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd59190614caa565b905061101b8960400151600081518110610ff157610ff1614c94565b6020026020010151338560008151811061100d5761100d614c94565b60200260200101518e61231c565b61102f838a602001518b604001518b61233d565b6040516370a0823160e01b81526001600160a01b0389811660048301528291908416906370a0823190602401602060405180830381865afa158015611078573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109c9190614caa565b6110a69190614cc3565b9550858a11156110d3576040516313fab00360e21b8152600481018b90526024810187905260440161063a565b505050505095945050505050565b7f000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111639190614cd6565b6001600160a01b0316336001600160a01b03161461119457604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b0383166111c45760001981146111b157806111b3565b475b90506111bf82826132c6565b505050565b60001981146111d3578061123b565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611217573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123b9190614caa565b90506111bf6001600160a01b03841683836137e1565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e9091169063659ac74b906084016020604051808303816000875af11580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ff9190614cd6565b95945050505050565b60008082804211156113365760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b60006113698c7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad738d61ffff166003613847565b90506000816001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf9190614cd6565b6001600160a01b03167f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b03161490508061140e579899985b60008061141f848e8e8e8e30613a66565b915091508261142f578082611432565b81815b80975081985050505050506114488c8786613bc8565b61145286846128a3565b50509850989650505050505050565b60008080806060808261149661147a60208a018a614cf3565b61148a60408b0160208c01614cf3565b8a604001356003613847565b9050806001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fa9190614cd6565b6001600160a01b031661151060208a018a614cf3565b6001600160a01b0316146115375760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad731661156e60208a018a614cf3565b6001600160a01b03161480156115875750348860600135145b156115ba576115ab61159f60408a0160208b01614cf3565b33838b6080013561231c565b6115b58134612dd6565b611691565b6001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad73166115f460408a0160208b01614cf3565b6001600160a01b031614801561160d5750348860800135145b1561162e576115ab61162260208a018a614cf3565b33838b6060013561231c565b61163b6020890189614cf3565b61164b60408a0160208b01614cf3565b60405163d0a4f13b60e01b81526001600160a01b03928316600482015291166024820152606089013560448201526080890135606482015234608482015260a40161063a565b61169b8882613be9565b949d939c50919a509850965090945092505050565b606081804211156116dd5760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b845151859015806116f5575080515160208201515114155b80611712575060408101515181515161170f906001614c81565b14155b156117305760405163b91b4d4d60e01b815260040160405180910390fd5b600061174987600001518860200151896040015161220c565b905061175f87602001518289604001518c612937565b9350878460008151811061177557611775614c94565b60200260200101511115611797578784600081518110610a6857610a68614c94565b6117b18760400151600081518110610e1457610e14614c94565b60006117c88289602001518a60400151888b612e8d565b905089811015610906576040516313fab00360e21b8152600481018b90526024810182905260440161063a565b604051630abcd78360e41b81526001600160801b03831660048201528115156024820152600090819081906001600160a01b0387169063abcd7830906044015b606060405180830381865afa158015611852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118769190614d10565b91989097509095509350505050565b600081804211156118b25760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b845151859015806118ca575080515160208201515114155b806118e757506040810151518151516118e4906001614c81565b14155b156119055760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b031686604001518760000151518151811061194a5761194a614c94565b60200260200101516001600160a01b0316146119785760408601518651518151811061070957610709614c94565b600061199187600001518860200151896040015161220c565b90506119ad8760400151600081518110610c2857610c28614c94565b6119c2898289602001518a6040015130613358565b9350838811156119ef576040516313fab00360e21b8152600481018990526024810185905260440161063a565b610c9486856128a3565b604051631cee6cdf60e31b81526001600160801b03831660048201528115156024820152600090819081906001600160a01b0387169063e77366f890604401611835565b600080808060608082611a5661147a60208a018a614cf3565b9050806001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190614cd6565b6001600160a01b0316611ad060208a018a614cf3565b6001600160a01b031614611af75760405163b33f8ab960e01b815260040160405180910390fd5b611b0761162260208a018a614cf3565b61169161159f60408a0160208b01614cf3565b60008180421115611b475760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580611b5f575080515160208201515114155b80611b7c5750604081015151815151611b79906001614c81565b14155b15611b9a5760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b03168660400151600081518110611bdb57611bdb614c94565b60200260200101516001600160a01b031614611c0857856040015160008151811061070957610709614c94565b6000611c2187600001518860200151896040015161220c565b9050611c4781600081518110611c3957611c39614c94565b602002602001015134612dd6565b611c5c348289602001518a604001518a613358565b935083881115611c89576040516313fab00360e21b8152600481018990526024810185905260440161063a565b505050949350505050565b6000808280421115611cc25760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b6000611cd58d8d8d61ffff166003613847565b90506000816001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614cd6565b6001600160a01b03168e6001600160a01b0316141590508015611d5c579899985b611d6a828c8c8c8c8c613a66565b90955093508015611d79579293925b505050995099975050505050505050565b604051634c7cffbd60e01b815262ffffff821660048201526000906001600160a01b03841690634c7cffbd90602401602060405180830381865afa158015611dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfa9190614caa565b90505b92915050565b60008180421115611e305760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b84515185901580611e48575080515160208201515114155b80611e655750604081015151815151611e62906001614c81565b14155b15611e835760405163b91b4d4d60e01b815260040160405180910390fd5b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b03168660400151600081518110611ec457611ec4614c94565b60200260200101516001600160a01b031614611ef157856040015160008151811061070957610709614c94565b6000611f0a87600001518860200151896040015161220c565b905060008760400151825181518110611f2557611f25614c94565b60209081029190910101516040516370a0823160e01b81526001600160a01b0389811660048301529192506000918316906370a0823190602401602060405180830381865afa158015611f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa09190614caa565b9050611fb883600081518110611c3957611c39614c94565b611fcc838a602001518b604001518b61233d565b6040516370a0823160e01b81526001600160a01b0389811660048301528291908416906370a0823190602401602060405180830381865afa158015612015573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120399190614caa565b6120439190614cc3565b9550858a1115612070576040516313fab00360e21b8152600481018b90526024810187905260440161063a565b5050505050949350505050565b7f000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ff9190614cd6565b6001600160a01b0316336001600160a01b03161461213057604051635d9515b960e11b815260040160405180910390fd5b6040516305feb5ff60e21b81526001600160a01b038716906317fad7fc9061216690309089908990899089908990600401614d9d565b600060405180830381600087803b15801561218057600080fd5b505af1158015612194573d6000803e3d6000fd5b50505050505050505050565b60405163f5e2932960e01b8152600481018290526000906001600160a01b0384169063f5e2932990602401602060405180830381865afa1580156121e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfa9190614ddd565b6060835167ffffffffffffffff8111156122285761222861441f565b604051908082528060200260200182016040528015612251578160200160208202803683370190505b5090506000808360008151811061226a5761226a614c94565b6020026020010151905060005b83518110156123125781925084816001018151811061229857612298614c94565b602002602001015191506122e083838984815181106122b9576122b9614c94565b60200260200101518985815181106122d3576122d3614c94565b602002602001015161408d565b8482815181106122f2576122f2614c94565b6001600160a01b0390921660209283029190910190910152600101612277565b5050509392505050565b8015612337576123376001600160a01b03851684848461418d565b50505050565b60008060008060008660008151811061235857612358614c94565b6020026020010151905060005b89518110156121945789818151811061238057612380614c94565b6020026020010151925088818151811061239c5761239c614c94565b602002602001015194508195508781600101815181106123be576123be614c94565b60200260200101519150895181600101146123f5578981600101815181106123e8576123e8614c94565b60200260200101516123f7565b865b9350600085600381111561240d5761240d614dfa565b036126b357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124779190614e27565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b031610156125ac576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa1580156124f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125179190614caa565b0390506000612527828585614202565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b15801561258d57600080fd5b505af11580156125a1573d6000803e3d6000fd5b5050505050506126ac565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa1580156125f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261b9190614caa565b039050600061262b828486614202565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b15801561269157600080fd5b505af11580156126a5573d6000803e3d6000fd5b5050505050505b505061289b565b60018560038111156126c7576126c7614dfa565b036127b257826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190614cd6565b60405160e083901b6001600160e01b03191681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af115801561278e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ac9190614e6c565b826001600160a01b03166353c059a0846001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128239190614cd6565b60405160e083901b6001600160e01b03191681526001600160a01b0391821686831614600482015290871660248201526044016020604051808303816000875af1158015612875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128999190614caa565b505b600101612365565b806000036128af575050565b604051632e1a7d4d60e01b8152600481018290527f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561291157600080fd5b505af1158015612925573d6000803e3d6000fd5b5050505061293382826132c6565b5050565b6060825167ffffffffffffffff8111156129535761295361441f565b60405190808252806020026020018201604052801561297c578160200160208202803683370190505b509050818185518151811061299357612993614c94565b602090810291909101015283515b8015612dcd576000846129b5600184614cc3565b815181106129c5576129c5614c94565b602002602001015190506000876001846129df9190614cc3565b815181106129ef576129ef614c94565b60200260200101519050600087600185612a099190614cc3565b81518110612a1957612a19614c94565b6020026020010151905060006003811115612a3657612a36614dfa565b826003811115612a4857612a48614dfa565b03612b6a57600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab29190614e27565b506001600160701b031691506001600160701b03169150888681518110612adb57612adb614c94565b60200260200101516001600160a01b0316856001600160a01b03161115612afe57905b6000878781518110612b1257612b12614c94565b60200260200101519050612b3183838361429c9092919063ffffffff16565b6001600160801b031688612b4660018a614cc3565b81518110612b5657612b56614c94565b602002602001018181525050505050612db7565b6001826003811115612b7e57612b7e614dfa565b03612cea577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635bdd4b7c82878781518110612bc557612bc5614c94565b6020026020010151866001600160a01b0316856001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c399190614cd6565b6040516001600160e01b031960e087901b1681526001600160a01b0394851660048201526001600160801b0390931660248401529092169190911460448201526064016040805180830381865afa158015612c98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbc9190614e6c565b5085612cc9600187614cc3565b81518110612cd957612cd9614c94565b602002602001018181525050612db7565b612d8381868681518110612d0057612d00614c94565b6020026020010151856001600160a01b0316846001600160a01b03166305e8746d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d749190614cd6565b6001600160a01b0316146117f5565b50506001600160801b031685612d9a600187614cc3565b81518110612daa57612daa614c94565b6020026020010181815250505b5050508080612dc590614e90565b9150506129a1565b50949350505050565b80600003612de2575050565b7f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad736001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612e3d57600080fd5b505af1158015612e51573d6000803e3d6000fd5b506129339350506001600160a01b037f0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad73169150849050836137e1565b60008060008060008088600081518110612ea957612ea9614c94565b6020026020010151905060005b8b518110156132b7578b8181518110612ed157612ed1614c94565b602002602001015193508a8181518110612eed57612eed614c94565b60200260200101519250819550898160010181518110612f0f57612f0f614c94565b602002602001015191508b518160010114612f46578b8160010181518110612f3957612f39614c94565b6020026020010151612f48565b875b94506000836003811115612f5e57612f5e614dfa565b0361306957888160010181518110612f7857612f78614c94565b60200260200101519650816001600160a01b0316866001600160a01b0316101561301c5760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03878116604484015260806064840152608483019190915285169063022c0d9f9060a4015b600060405180830381600087803b158015612fff57600080fd5b505af1158015613013573d6000803e3d6000fd5b505050506132af565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03878116604484015260806064840152608483019190915285169063022c0d9f9060a401612fe5565b600183600381111561307d5761307d614dfa565b03613185576000846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e69190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052888316602483015292506000918291908816906353c059a09060440160408051808303816000875af1158015613143573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131679190614e6c565b9150915082156131795780995061317d565b8199505b5050506132af565b6000846001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156131c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e99190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052888316602483015292506000918291613283918916906353c059a0906044015b6020604051808303816000875af115801561324b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326f9190614caa565b6001600160801b0381169160809190911c90565b6001600160801b031691506001600160801b0316915082156132a7578099506132ab565b8199505b5050505b600101612eb6565b50505050505095945050505050565b806000036132d2575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461331f576040519150601f19603f3d011682016040523d82523d6000602084013e613324565b606091505b50509050806111bf5760405163047b96f760e41b81526001600160a01b03841660048201526024810183905260440161063a565b6000806000806000808760008151811061337457613374614c94565b602002602001015190508a955060005b8a518110156132b7578a818151811061339f5761339f614c94565b602002602001015192508981815181106133bb576133bb614c94565b602002602001015194508195508881600101815181106133dd576133dd614c94565b602002602001015191508a518160010114613414578a816001018151811061340757613407614c94565b6020026020010151613416565b875b9350600085600381111561342c5761342c614dfa565b036135e657600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134969190614e27565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613555576134d2898383614202565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561353857600080fd5b505af115801561354c573d6000803e3d6000fd5b505050506135df565b613560898284614202565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156135c657600080fd5b505af11580156135da573d6000803e3d6000fd5b505050505b50506137d9565b60018560038111156135fa576135fa614dfa565b03613702576000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561363f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136639190614cd6565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af11580156136c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e49190614e6c565b9150915082156136f6578099506136fa565b8199505b5050506137d9565b6000836001600160a01b031663da10610c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613742573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137669190614cd6565b60405163029e02cd60e51b81526001600160a01b0391821685831614600482018190528783166024830152925060009182916137ad918816906353c059a09060440161322c565b6001600160801b031691506001600160801b0316915082156137d1578099506137d5565b8199505b5050505b600101613384565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b179052612337848261433b565b6000600182600381111561385d5761385d614dfa565b036139075760405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063704037bd906064015b608060405180830381865afa1580156138d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fc9190614ea7565b602001519050613a1d565b600282600381111561391b5761391b614dfa565b0361397d5760405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f0000000000000000000000000000000000000000000000000000000000000000169063704037bd906064016138bb565b60405163704037bd60e01b81526001600160a01b0386811660048301528581166024830152604482018590527f000000000000000000000000f8e7505380c3c9c949b071e374fe9b3ae5ff752e169063704037bd90606401608060405180830381865afa1580156139f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a169190614ea7565b6020015190505b6001600160a01b038116613a5e57604051636b2471d160e11b81526001600160a01b038087166004830152851660248201526044810184905260640161063a565b949350505050565b6000806000886001600160a01b031663c9939f5e338689896040518563ffffffff1660e01b8152600401613a9d9493929190614f0e565b6000604051808303816000875af1158015613abc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ae49190810190614f4c565b905060005b8151811015613b7857613b1b828281518110613b0757613b07614c94565b60200260200101516001600160801b031690565b613b2e906001600160801b031685614c81565b9350613b53828281518110613b4557613b45614c94565b602002602001015160801c90565b613b66906001600160801b031684614c81565b9250613b7181614fd2565b9050613ae9565b5087831080613b8657508682105b15613bbc576040516318ccfb7760e11b81526004810189905260248101849052604481018890526064810183905260840161063a565b50965096945050505050565b80600003613bd557505050565b6111bf6001600160a01b03841683836137e1565b600080600080606080876101c0013580421115613c225760405163dae7ca7d60e01b81526004810182905242602482015260440161063a565b613c306101408a018a614feb565b9050613c406101208b018b614feb565b9050141580613c6d5750613c586101608a018a614feb565b9050613c686101208b018b614feb565b905014155b15613c8b5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08a01351180613ca7575062ffffff6101008a0135115b15613cd65760405163197a55c760e11b815260e08a013560048201526101008a0135602482015260440161063a565b6000613ce66101208b018b614feb565b905067ffffffffffffffff811115613d0057613d0061441f565b604051908082528060200260200182016040528015613d29578160200160208202803683370190505b509050613d3a6101208b018b614feb565b905067ffffffffffffffff811115613d5457613d5461441f565b604051908082528060200260200182016040528015613d7d578160200160208202803683370190505b5093506000896001600160a01b031663dbe65edc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de49190614ddd565b62ffffff169050808b61010001358c60e00135011080613e0e57508a60e001358b61010001358201105b15613e4457604051637d50edab60e11b815260e08c013560048201526101008c013560248201526044810182905260640161063a565b60005b8251811015613f47576000613e606101208e018e614feb565b83818110613e7057613e70614c94565b90506020020135830190506000811280613e8c575062ffffff81115b15613ead576040516370a82e6160e11b81526004810182905260240161063a565b80878381518110613ec057613ec0614c94565b6020908102919091010152613f21613edc6101408f018f614feb565b84818110613eec57613eec614c94565b905060200201358e806101600190613f049190614feb565b85818110613f1457613f14614c94565b90506020020135836143ab565b848381518110613f3357613f33614c94565b602090810291909101015250600101613e47565b50506000808a6001600160a01b031663383d15c58d610180016020810190613f6f9190614cf3565b858f6101a0016020810190613f849190614cf3565b6040518463ffffffff1660e01b8152600401613fa293929190615035565b6000604051808303816000875af1158015613fc1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613fe99190810190615099565b965090925090506000613ffc83836143e5565b6001600160801b0381169b50608081901c9a50905060a08d01358b108061402657508c60c001358a105b15614062576040516318ccfb7760e11b815260a08e01356004820152602481018c905260c08e01356044820152606481018b905260840161063a565b6001600160801b0382169850608082901c6001600160801b0316975050505050509295509295509295565b6000808260038111156140a2576140a2614dfa565b036141815760405163e6a4390560e01b81526001600160a01b03868116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e6a4390590604401602060405180830381865afa158015614115573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141399190614cd6565b90506001600160a01b03811661417c57604051636b2471d160e11b81526001600160a01b038087166004830152851660248201526044810184905260640161063a565b613a5e565b6112ff85858585613847565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b1790526141fb858261433b565b5050505050565b6000836000036142255760405163b229ed3360e01b815260040160405180910390fd5b821580614230575081155b1561424e576040516398c59a2960e01b815260040160405180910390fd5b600061425c856103e561513f565b9050600061426a848361513f565b905060008261427b876103e861513f565b6142859190614c81565b90506142918183615156565b979650505050505050565b6000836000036142bf5760405163b229ed3360e01b815260040160405180910390fd5b8215806142ca575081155b156142e8576040516398c59a2960e01b815260040160405180910390fd5b60006142f4858561513f565b614300906103e861513f565b9050600061430e8685614cc3565b61431a906103e561513f565b90506143268183615156565b614331906001614c81565b9695505050505050565b600080600052602060008351602085016000875af1905080801561437c573d801561436f5760016000511483169250614376565b843b151592505b5061438c565b3d1561438c573d6000803e3d6000fd5b50806111bf5760405163197138bd60e11b815260040160405180910390fd5b601882901b6affffffffffffffff00000016605884901b72ffffffffffffffff0000000000000000000000161762ffffff82168117613a5e565b8082038281118061440157506001600160801b03808416908216115b15611dfd5760405163e599af5560e01b815260040160405180910390fd5b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156144585761445861441f565b60405290565b6040516080810167ffffffffffffffff811182821017156144585761445861441f565b604051601f8201601f1916810167ffffffffffffffff811182821017156144aa576144aa61441f565b604052919050565b600067ffffffffffffffff8211156144cc576144cc61441f565b5060051b60200190565b600082601f8301126144e757600080fd5b813560206144fc6144f7836144b2565b614481565b82815260059290921b8401810191818101908684111561451b57600080fd5b8286015b84811015614536578035835291830191830161451f565b509695505050505050565b6001600160a01b038116811461455657600080fd5b50565b803561456481614541565b919050565b600082601f83011261457a57600080fd5b8135602061458a6144f7836144b2565b82815260059290921b840181019181810190868411156145a957600080fd5b8286015b848110156145365780356145c081614541565b83529183019183016145ad565b6000606082840312156145df57600080fd5b6145e7614435565b9050813567ffffffffffffffff8082111561460157600080fd5b61460d858386016144d6565b835260209150818401358181111561462457600080fd5b8401601f8101861361463557600080fd5b80356146436144f7826144b2565b81815260059190911b8201840190848101908883111561466257600080fd5b928501925b8284101561468e5783356004811061467f5760008081fd5b82529285019290850190614667565b80868801525050505060408401359150808211156146ab57600080fd5b506146b884828501614569565b60408301525092915050565b600080600080600060a086880312156146dc57600080fd5b8535945060208601359350604086013567ffffffffffffffff81111561470157600080fd5b61470d888289016145cd565b935050606086013561471e81614541565b949793965091946080013592915050565b6000806000806080858703121561474557600080fd5b84359350602085013567ffffffffffffffff81111561476357600080fd5b61476f878288016145cd565b935050604085013561478081614541565b9396929550929360600135925050565b600081518084526020808501945080840160005b838110156147c0578151875295820195908201906001016147a4565b509495945050505050565b602081526000611dfa6020830184614790565b6000806000606084860312156147f357600080fd5b83356147fe81614541565b9250602084013561480e81614541565b929592945050506040919091013590565b62ffffff8116811461455657600080fd5b61ffff8116811461455657600080fd5b803561456481614830565b6000806000806080858703121561486157600080fd5b843561486c81614541565b9350602085013561487c81614541565b9250604085013561488c8161481f565b9150606085013561489c81614830565b939692955090935050565b600080600080600080600080610100898b0312156148c457600080fd5b88356148cf81614541565b975060208901356148df81614830565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561490a57600080fd5b6149168c838d016144d6565b955060a08b013591508082111561492c57600080fd5b506149398b828c016144d6565b93505060c089013561494a81614541565b8092505060e089013590509295985092959890939650565b60006020828403121561497457600080fd5b813567ffffffffffffffff81111561498b57600080fd5b82016101e0818503121561499e57600080fd5b9392505050565b86815285602082015284604082015283606082015260c0608082015260006149d060c0830185614790565b82810360a08401526149e28185614790565b9998505050505050505050565b6001600160801b038116811461455657600080fd5b801515811461455657600080fd5b600080600060608486031215614a2757600080fd5b8335614a3281614541565b92506020840135614a42816149ef565b91506040840135614a5281614a04565b809150509250925092565b60008060008060008060008060006101208a8c031215614a7c57600080fd5b8935614a8781614541565b985060208a0135614a9781614541565b9750614aa560408b01614840565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff80821115614ad057600080fd5b614adc8d838e016144d6565b955060c08c0135915080821115614af257600080fd5b50614aff8c828d016144d6565b935050614b0e60e08b01614559565b91506101008a013590509295985092959850929598565b60008060408385031215614b3857600080fd5b8235614b4381614541565b91506020830135614b538161481f565b809150509250929050565b60008083601f840112614b7057600080fd5b50813567ffffffffffffffff811115614b8857600080fd5b6020830191508360208260051b8501011115614ba357600080fd5b9250929050565b60008060008060008060808789031215614bc357600080fd5b8635614bce81614541565b95506020870135614bde81614541565b9450604087013567ffffffffffffffff80821115614bfb57600080fd5b614c078a838b01614b5e565b90965094506060890135915080821115614c2057600080fd5b50614c2d89828a01614b5e565b979a9699509497509295939492505050565b60008060408385031215614c5257600080fd5b8235614c5d81614541565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dfd57611dfd614c6b565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614cbc57600080fd5b5051919050565b81810381811115611dfd57611dfd614c6b565b600060208284031215614ce857600080fd5b815161499e81614541565b600060208284031215614d0557600080fd5b813561499e81614541565b600080600060608486031215614d2557600080fd5b8351614d30816149ef565b6020850151909350614d41816149ef565b6040850151909250614a52816149ef565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614d8457600080fd5b8260051b80836020870137939093016020019392505050565b60006001600160a01b03808916835280881660208401525060806040830152614dca608083018688614d52565b82810360608401526149e2818587614d52565b600060208284031215614def57600080fd5b815161499e8161481f565b634e487b7160e01b600052602160045260246000fd5b80516001600160701b038116811461456457600080fd5b600080600060608486031215614e3c57600080fd5b614e4584614e10565b9250614e5360208501614e10565b9150604084015163ffffffff81168114614a5257600080fd5b60008060408385031215614e7f57600080fd5b505080516020909101519092909150565b600081614e9f57614e9f614c6b565b506000190190565b600060808284031215614eb957600080fd5b614ec161445e565b8251614ecc81614830565b81526020830151614edc81614541565b60208201526040830151614eef81614a04565b60408201526060830151614f0281614a04565b60608201529392505050565b60006001600160a01b03808716835280861660208401525060806040830152614f3a6080830185614790565b82810360608401526142918185614790565b60006020808385031215614f5f57600080fd5b825167ffffffffffffffff811115614f7657600080fd5b8301601f81018513614f8757600080fd5b8051614f956144f7826144b2565b81815260059190911b82018301908381019087831115614fb457600080fd5b928401925b8284101561429157835182529284019290840190614fb9565b600060018201614fe457614fe4614c6b565b5060010190565b6000808335601e1984360301811261500257600080fd5b83018035915067ffffffffffffffff82111561501d57600080fd5b6020019150600581901b3603821315614ba357600080fd5b6000606082016001600160a01b0380871684526020606081860152828751808552608087019150828901945060005b8181101561508057855183529483019491830191600101615064565b5050809450505080851660408501525050949350505050565b6000806000606084860312156150ae57600080fd5b835192506020808501519250604085015167ffffffffffffffff8111156150d457600080fd5b8501601f810187136150e557600080fd5b80516150f36144f7826144b2565b81815260059190911b8201830190838101908983111561511257600080fd5b928401925b8284101561513057835182529284019290840190615117565b80955050505050509250925092565b8082028115828204841417611dfd57611dfd614c6b565b60008261517357634e487b7160e01b600052601260045260246000fd5b50049056fea264697066735822122086d27368cbc63b44b36322b62f96bb4f9fb949db443e6d2465bc5b838863f03464736f6c63430008140033
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| no event logs emitted by this address | |||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| 0x03bd0d04…b35fca | Transfer | 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x5c94…8677 | OUT | 0x0000…0000 | 0.000015 WETH | WETH (WETH) | |
| 0x03bd0d04…b35fca | Transfer | 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x5c94…8677 | OUT | 0x86c0…c3ec | 8,939,354.570721 BLOCKY | BLOCKY (BLOCKY) | |
| 0x03bd0d04…b35fca | Transfer | 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 0.000015 WETH | WETH (WETH) | |
| 0x03bd0d04…b35fca | Transfer | 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 8,939,354.570721 BLOCKY | BLOCKY (BLOCKY) | |
| 0x2a91be3a…168e06 | Transfer | 21,757,934 | 20 days agoTue, 28 Jul 2026 17:05:45 UTC | 0x5c94…8677 | OUT | 0x4659…bbc5 | 10,449,756.701989 BLOCKY | BLOCKY (BLOCKY) | |
| 0x2a91be3a…168e06 | Transfer | 21,757,934 | 20 days agoTue, 28 Jul 2026 17:05:45 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 10,449,756.701989 BLOCKY | BLOCKY (BLOCKY) | |
| 0x9ca406dc…605b2f | Transfer | 21,645,445 | 20 days agoTue, 28 Jul 2026 13:57:50 UTC | 0x5c94…8677 | OUT | 0x1afb…8936 | 0.1 WETH | WETH (WETH) | |
| 0x9ca406dc…605b2f | Transfer | 21,645,445 | 20 days agoTue, 28 Jul 2026 13:57:50 UTC | 0x0000…0000 | IN | 0x5c94…8677 | 0.1 WETH | WETH (WETH) | |
| 0x34ff49d0…8c6239 | Transfer | 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x5c94…8677 | OUT | 0x0000…0000 | 0.099497 WETH | WETH (WETH) | |
| 0x34ff49d0…8c6239 | Transfer | 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x5c94…8677 | OUT | 0x25d4…82e4 | 2,011,711.170390 BLOCKY | BLOCKY (BLOCKY) | |
| 0x34ff49d0…8c6239 | Transfer | 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 0.099497 WETH | WETH (WETH) | |
| 0x34ff49d0…8c6239 | Transfer | 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 2,011,711.170390 BLOCKY | BLOCKY (BLOCKY) | |
| 0xe45a2c51…171720 | Transfer | 20,660,405 | 21 days agoMon, 27 Jul 2026 10:28:36 UTC | 0x5c94…8677 | OUT | 0x1afb…8936 | 0.1 WETH | WETH (WETH) | |
| 0xe45a2c51…171720 | Transfer | 20,660,405 | 21 days agoMon, 27 Jul 2026 10:28:36 UTC | 0x0000…0000 | IN | 0x5c94…8677 | 0.1 WETH | WETH (WETH) | |
| 0xd171d897…ae3efe | Transfer | 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0x5c94…8677 | OUT | 0x0000…0000 | 0.098364 WETH | WETH (WETH) | |
| 0xd171d897…ae3efe | Transfer | 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0x5c94…8677 | OUT | 0x86c0…c3ec | 2,041,326.494895 BLOCKY | BLOCKY (BLOCKY) | |
| 0xd171d897…ae3efe | Transfer | 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 0.098364 WETH | WETH (WETH) | |
| 0xd171d897…ae3efe | Transfer | 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 2,041,326.494895 BLOCKY | BLOCKY (BLOCKY) | |
| 0xb8644e7b…c281cc | Transfer | 20,653,569 | 21 days agoMon, 27 Jul 2026 10:17:10 UTC | 0x5c94…8677 | OUT | 0x1afb…8936 | 0.1 WETH | WETH (WETH) | |
| 0xb8644e7b…c281cc | Transfer | 20,653,569 | 21 days agoMon, 27 Jul 2026 10:17:10 UTC | 0x0000…0000 | IN | 0x5c94…8677 | 0.1 WETH | WETH (WETH) | |
| 0x02a36e82…d9443c | Transfer | 19,665,560 | 22 days agoSun, 26 Jul 2026 06:45:19 UTC | 0x5c94…8677 | OUT | 0x0000…0000 | 0.668704 WETH | WETH (WETH) | |
| 0x02a36e82…d9443c | Transfer | 19,665,560 | 22 days agoSun, 26 Jul 2026 06:45:19 UTC | 0x1afb…8936 | IN | 0x5c94…8677 | 0.668704 WETH | WETH (WETH) | |
| 0x0af13027…b5dee5 | Transfer | 19,163,196 | 23 days agoSat, 25 Jul 2026 16:45:00 UTC | 0x5c94…8677 | OUT | 0x1afb…8936 | 0.2 WETH | WETH (WETH) | |
| 0x0af13027…b5dee5 | Transfer | 19,163,196 | 23 days agoSat, 25 Jul 2026 16:45:00 UTC | 0x0000…0000 | IN | 0x5c94…8677 | 0.2 WETH | WETH (WETH) |
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| 0x03bd0d…b35fca | removeLiquidityNATIVE | 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x86c0…c3ec | IN | LBRouter | $0.000 ETH | 0.00002596 | |
| 0x2a91be…168e06 | removeLiquidityNATIVE | 21,757,934 | 20 days agoTue, 28 Jul 2026 17:05:45 UTC | 0x4659…bbc5 | IN | LBRouter | $0.000 ETH | 0.00003415 | |
| 0x9ca406…605b2f | addLiquidityNATIVE | 21,645,445 | 20 days agoTue, 28 Jul 2026 13:57:50 UTC | 0x86c0…c3ec | IN | LBRouter | $189.260.1 ETH | 0.00012364 | |
| 0xa08322…e5313f | addLiquidityNATIVE | 20,856,493 | 21 days agoMon, 27 Jul 2026 15:56:13 UTC | 0x4659…bbc5 | IN | LBRouter | $0.000 ETH | 0.00014651 | |
| 0x34ff49…8c6239 | removeLiquidityNATIVE | 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x25d4…82e4 | IN | LBRouter | $0.000 ETH | 0.00002912 | |
| 0xe45a2c…171720 | addLiquidityNATIVE | 20,660,405 | 21 days agoMon, 27 Jul 2026 10:28:36 UTC | 0x25d4…82e4 | IN | LBRouter | $189.260.1 ETH | 0.00007024 | |
| 0xd171d8…ae3efe | removeLiquidityNATIVE | 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0x86c0…c3ec | IN | LBRouter | $0.000 ETH | 0.00001724 | |
| 0xb8644e…c281cc | addLiquidityNATIVE | 20,653,569 | 21 days agoMon, 27 Jul 2026 10:17:10 UTC | 0x86c0…c3ec | IN | LBRouter | $189.260.1 ETH | 0.00003864 | |
| 0x02a36e…d9443c | removeLiquidityNATIVE | 19,665,560 | 22 days agoSun, 26 Jul 2026 06:45:19 UTC | 0x86c0…c3ec | IN | LBRouter | $0.000 ETH | 0.00004563 | |
| 0xa73fb6…fb217b | addLiquidityNATIVE | 19,254,544 | 23 days agoSat, 25 Jul 2026 19:17:43 UTC | 0x8baa…c798 | IN | LBRouter | $0.000 ETH | 0.00024053 | |
| 0x0af130…b5dee5 | addLiquidityNATIVE | 19,163,196 | 23 days agoSat, 25 Jul 2026 16:45:00 UTC | 0x86c0…c3ec | IN | LBRouter | $378.520.2 ETH | 0.00025678 | |
| 0xaec090…6f01dc | createLBPair | 19,163,041 | 23 days agoSat, 25 Jul 2026 16:44:44 UTC | 0x86c0…c3ec | IN | LBRouter | $0.000 ETH | 0.00002375 |
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x03bd0d…b35fca | CALL | removeLiquidityNATIVE | 0x5c94…8677 | OUT | 0x86c0…c3ec | 0.00001 ETH |
| 24,525,565 | 17 days agoFri, 31 Jul 2026 22:09:47 UTC | 0x03bd0d…b35fca | CALL | removeLiquidityNATIVE | 0x0bd7…ad73 | IN | 0x5c94…8677 | 0.00001 ETH |
| 21,645,445 | 20 days agoTue, 28 Jul 2026 13:57:50 UTC | 0x9ca406…605b2f | CALL | addLiquidityNATIVE | 0x5c94…8677 | OUT | 0x0bd7…ad73 | 0.1 ETH |
| 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x34ff49…8c6239 | CALL | removeLiquidityNATIVE | 0x5c94…8677 | OUT | 0x25d4…82e4 | 0.09949 ETH |
| 20,663,545 | 21 days agoMon, 27 Jul 2026 10:33:51 UTC | 0x34ff49…8c6239 | CALL | removeLiquidityNATIVE | 0x0bd7…ad73 | IN | 0x5c94…8677 | 0.09949 ETH |
| 20,660,405 | 21 days agoMon, 27 Jul 2026 10:28:36 UTC | 0xe45a2c…171720 | CALL | addLiquidityNATIVE | 0x5c94…8677 | OUT | 0x0bd7…ad73 | 0.1 ETH |
| 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0xd171d8…ae3efe | CALL | removeLiquidityNATIVE | 0x5c94…8677 | OUT | 0x86c0…c3ec | 0.09836 ETH |
| 20,656,123 | 21 days agoMon, 27 Jul 2026 10:21:27 UTC | 0xd171d8…ae3efe | CALL | removeLiquidityNATIVE | 0x0bd7…ad73 | IN | 0x5c94…8677 | 0.09836 ETH |
| 20,653,569 | 21 days agoMon, 27 Jul 2026 10:17:10 UTC | 0xb8644e…c281cc | CALL | addLiquidityNATIVE | 0x5c94…8677 | OUT | 0x0bd7…ad73 | 0.1 ETH |
| 19,665,560 | 22 days agoSun, 26 Jul 2026 06:45:19 UTC | 0x02a36e…d9443c | CALL | removeLiquidityNATIVE | 0x5c94…8677 | OUT | 0x86c0…c3ec | 0.66870 ETH |
| 19,665,560 | 22 days agoSun, 26 Jul 2026 06:45:19 UTC | 0x02a36e…d9443c | CALL | removeLiquidityNATIVE | 0x0bd7…ad73 | IN | 0x5c94…8677 | 0.66870 ETH |
| 19,163,196 | 23 days agoSat, 25 Jul 2026 16:45:00 UTC | 0x0af130…b5dee5 | CALL | addLiquidityNATIVE | 0x5c94…8677 | OUT | 0x0bd7…ad73 | 0.2 ETH |