Contract 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 2

Txn Hash Method
Block
From
To
Value [Txn Fee]
0x6cbd9e466252499fdacffc1ca6a854afdf570c32738c6676b37927eb09c365f1Swap AVAX For Ex...229782722022-11-29 4:51:0511 secs ago0x88042000f71044a9e2828dd4fea94aafbca577fd IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.161643533457321 AVAX0.007859996383 26.8818
0xd64740117fc0946b33b27d655eee4e87be3d863f818a2177a60b00fc0ce355c7Swap Exact Token...229782682022-11-29 4:50:5620 secs ago0xb095ad5cc61e75458505ca45d58dd177907eb8c0 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.004297661857 26.825346
0xb477a40344be0b2521f85ad5300385ab7a01acb996c55ed305b6361f2586da8bSwap Exact Token...229782492022-11-29 4:50:1957 secs ago0x51738410116c62f3284f7852f24953d5825acdf1 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0043149798 26.94
0x8c815d6aec57d8f1611f470dd5b74929af209212693c17b6531559f9b407af83Swap AVAX For Ex...229782362022-11-29 4:49:531 min ago0x9abf3bd870ee33a1000ed2cadfa5e85fb94c75af IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.913557078436672 AVAX0.004595103 27
0x7dbe4a00cf7069c7cdf0be28e8bb3c215521d93b041622afd0630a1f9d5821acSwap Exact AVAX ...229782192022-11-29 4:49:162 mins ago0xc35876c3389a934089ddbe9ae923f7b791ca8374 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.04 AVAX0.003858450467 26.825346
0x88e794667ba01b8f18ac2c976ba0102b6da01a485c367d489f2749312f7ddf73Swap Exact Token...229782112022-11-29 4:49:002 mins ago0x5cf4a2ee46b741cbc19bb666ca16683daee2f6bd IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.003969859 26.5
0x8baf2fa269430450c3eb687df9bc1b98a9bcc18c3ff7ee61e2851228ad5c6233Swap Exact AVAX ...229782032022-11-29 4:48:442 mins ago0x9a7b12b24646f182eb34fb3bd244d1a31ec36210 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.001 AVAX0.0038866338 26.94
0xe38ff72c95080fc1afaae790d9eefe7e0f5ee404e084a753905203328a20d164Swap Exact Token...229781912022-11-29 4:48:202 mins ago0x0f985e864fb5791d812edbe6009cd1f7a5e398a7 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.00407054689 26.41
0xbb6e28b08cc001a9cc65e2d56b62c80e4696ade4e85e176d80a4ec31b7481b7eSwap Exact AVAX ...229781732022-11-29 4:47:433 mins ago0x0fc0ebe63b74c3c90731a3cdae03c9a51b084f36 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.4 AVAX0.004275423743 26.565987368
0xae296a742828eda691c65c883740389ec44be91dc9aba5a125d18a5fa83af5e4Swap Exact Token...229781672022-11-29 4:47:303 mins ago0x93e7630d95d4edd7566180d2cc4867925375b030 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.004110635266 26.665944009
0x39f1ea6b582dd9031d80921fcf68c91f40b48680215a2be5c1b68f4ac8580d61Swap Exact Token...229781522022-11-29 4:47:004 mins ago0x035edbb504d43b8578c22cf2d8497b708770cab6 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.003981307 26.5
0x21244acde3c48562d0050e610d0a05b583cd428996d966aadf0e833953440421Swap Exact Token...229781512022-11-29 4:46:584 mins ago0xc263087c5a4196aa9c42d82b352b8a6d1118dd1b IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0076251895 26.5
0xb6c770d1b9d9174197609879f60688769f2e5c8d058cee754c97d214b4431900Swap Exact Token...229781312022-11-29 4:46:174 mins ago0x209004b5972e3d9590acc3610e21093fbd68ecc7 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.003924703 26.5
0x3154119da5758b0bbc7ab24b5f26988f8741d82cf43db2a2dfbcdcf1c11a666fSwap Exact AVAX ...229781282022-11-29 4:46:105 mins ago0xc263087c5a4196aa9c42d82b352b8a6d1118dd1b IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c32.49 AVAX0.006667559 26.5
0x735b1ae3ef4c6a5551f762ac8c7ab8efc0b17cc2ef94c62a58c7098e33655e4dSwap Exact Token...229781182022-11-29 4:45:475 mins ago0x0fc0ebe63b74c3c90731a3cdae03c9a51b084f36 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.00369166903 26.41
0xa6ce8b7a993db5727067d8dcc4c6858f33739917de8005c4efb514e4eee27ea2Swap Exact Token...229781142022-11-29 4:45:395 mins ago0x9d09cea6abcc460ede3c89731ab6f829a556413a IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.003851934 26.5
0x0e50f99e66b0eeb4705156eee44c8091bc18ee528e13ae64cb1cb112958c676dSwap Exact Token...229781122022-11-29 4:45:345 mins ago0xc263087c5a4196aa9c42d82b352b8a6d1118dd1b IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0061131525 26.5
0xb8980aa6057c098681c6cd210b45b8adccca62a6eb403c59760ca8e9a482f182Swap Exact AVAX ...229781072022-11-29 4:45:255 mins ago0x8e039d515f95d7b64c19ce877633bd7a5a58ff43 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c315 AVAX0.0034425355 26.5
0xf4eddf429870cac8cb85d7143ba650e34c91ffcb7e3528f57119e0e3ed944c10Swap Exact Token...229781022022-11-29 4:45:116 mins ago0x66001fb5f11abc3a63fa276538fc76102c11f3e5 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.003744715 26.5
0x98c9a118fd5d20386f44457c630d918e26a13d8026c9c097919fce20290a9ba2Swap Exact Token...229780942022-11-29 4:44:536 mins ago0xbd79c5021ca8e85b5495f4f9a2971df038448574 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0062224385 26.5
0x6333b2839d96533d28f98d75d6fb331ae188213ed70e89b0b69347f780462cc3Swap Exact Token...229780932022-11-29 4:44:516 mins ago0x01863b065d8d8ed5397b266df2d121384e0b7d40 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0038917105 26.5
0x1b01d3459927d91582a341cb8ef958e5ee5c3d403175fb56c6f669dfd42968b3Swap Exact Token...229780802022-11-29 4:44:256 mins ago0x8ebe449bc354e8b096526da3b54214f770f29cec IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0033563045 26.5
0x05b52bb85b00b1a356694b8b790a78113014f1d160de09392753eff92d9aae72Swap Exact AVAX ...229780802022-11-29 4:44:256 mins ago0xa58257328069a48621fa12ba25286020fee60439 IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.8 AVAX0.004311718429 26.717468051
0x88b835666875c7416ba655bf2d13aaf4c6e690879733cee049c579b545a4c900Swap Exact Token...229780702022-11-29 4:44:057 mins ago0x8ebe449bc354e8b096526da3b54214f770f29cec IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0070818335 26.5
0x740767f30704b03e02adfa5040b392d28475a91889b1985b8caf1e6d24580eeeSwap Tokens For ...229780602022-11-29 4:43:447 mins ago0xc7978fc247c84ae009148de9914a38114f6aeb9b IN  0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30 AVAX0.0074052925 26.5
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xd64740117fc0946b33b27d655eee4e87be3d863f818a2177a60b00fc0ce355c7229782682022-11-29 4:50:5620 secs ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30xb095ad5cc61e75458505ca45d58dd177907eb8c00.000799617897863825 AVAX
0xd64740117fc0946b33b27d655eee4e87be3d863f818a2177a60b00fc0ce355c7229782682022-11-29 4:50:5620 secs ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.000799617897863825 AVAX
0xb477a40344be0b2521f85ad5300385ab7a01acb996c55ed305b6361f2586da8b229782492022-11-29 4:50:1957 secs ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x51738410116c62f3284f7852f24953d5825acdf10.139304850828123385 AVAX
0xb477a40344be0b2521f85ad5300385ab7a01acb996c55ed305b6361f2586da8b229782492022-11-29 4:50:1957 secs ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.139304850828123385 AVAX
0x8c815d6aec57d8f1611f470dd5b74929af209212693c17b6531559f9b407af83229782362022-11-29 4:49:531 min ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x9abf3bd870ee33a1000ed2cadfa5e85fb94c75af0.004545060091724741 AVAX
0x8c815d6aec57d8f1611f470dd5b74929af209212693c17b6531559f9b407af83229782362022-11-29 4:49:531 min ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX0.909012018344948256 AVAX
0x7dbe4a00cf7069c7cdf0be28e8bb3c215521d93b041622afd0630a1f9d5821ac229782192022-11-29 4:49:162 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX0.04 AVAX
0x88e794667ba01b8f18ac2c976ba0102b6da01a485c367d489f2749312f7ddf73229782112022-11-29 4:49:002 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x5cf4a2ee46b741cbc19bb666ca16683daee2f6bd12.116680916718006213 AVAX
0x88e794667ba01b8f18ac2c976ba0102b6da01a485c367d489f2749312f7ddf73229782112022-11-29 4:49:002 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c312.116680916718006213 AVAX
0x8baf2fa269430450c3eb687df9bc1b98a9bcc18c3ff7ee61e2851228ad5c6233229782032022-11-29 4:48:442 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX0.001 AVAX
0xe38ff72c95080fc1afaae790d9eefe7e0f5ee404e084a753905203328a20d164229781912022-11-29 4:48:202 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x0f985e864fb5791d812edbe6009cd1f7a5e398a70.016336587307482086 AVAX
0xe38ff72c95080fc1afaae790d9eefe7e0f5ee404e084a753905203328a20d164229781912022-11-29 4:48:202 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.016336587307482086 AVAX
0xbb6e28b08cc001a9cc65e2d56b62c80e4696ade4e85e176d80a4ec31b7481b7e229781732022-11-29 4:47:433 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX0.4 AVAX
0xae296a742828eda691c65c883740389ec44be91dc9aba5a125d18a5fa83af5e4229781672022-11-29 4:47:303 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x93e7630d95d4edd7566180d2cc4867925375b0300.138774784839179919 AVAX
0xae296a742828eda691c65c883740389ec44be91dc9aba5a125d18a5fa83af5e4229781672022-11-29 4:47:303 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.138774784839179919 AVAX
0x39f1ea6b582dd9031d80921fcf68c91f40b48680215a2be5c1b68f4ac8580d61229781522022-11-29 4:47:004 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x035edbb504d43b8578c22cf2d8497b708770cab60.487355973676161858 AVAX
0x39f1ea6b582dd9031d80921fcf68c91f40b48680215a2be5c1b68f4ac8580d61229781522022-11-29 4:47:004 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.487355973676161858 AVAX
0xb6c770d1b9d9174197609879f60688769f2e5c8d058cee754c97d214b4431900229781312022-11-29 4:46:174 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x209004b5972e3d9590acc3610e21093fbd68ecc70.051028755883854051 AVAX
0xb6c770d1b9d9174197609879f60688769f2e5c8d058cee754c97d214b4431900229781312022-11-29 4:46:174 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.051028755883854051 AVAX
0x3154119da5758b0bbc7ab24b5f26988f8741d82cf43db2a2dfbcdcf1c11a666f229781282022-11-29 4:46:105 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX2.49 AVAX
0x735b1ae3ef4c6a5551f762ac8c7ab8efc0b17cc2ef94c62a58c7098e33655e4d229781182022-11-29 4:45:475 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x0fc0ebe63b74c3c90731a3cdae03c9a51b084f360.509142107625318328 AVAX
0x735b1ae3ef4c6a5551f762ac8c7ab8efc0b17cc2ef94c62a58c7098e33655e4d229781182022-11-29 4:45:475 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30.509142107625318328 AVAX
0xa6ce8b7a993db5727067d8dcc4c6858f33739917de8005c4efb514e4eee27ea2229781142022-11-29 4:45:395 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c30x9d09cea6abcc460ede3c89731ab6f829a556413a22.57237761878927605 AVAX
0xa6ce8b7a993db5727067d8dcc4c6858f33739917de8005c4efb514e4eee27ea2229781142022-11-29 4:45:395 mins ago Wrapped AVAX 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c322.57237761878927605 AVAX
0xb8980aa6057c098681c6cd210b45b8adccca62a6eb403c59760ca8e9a482f182229781072022-11-29 4:45:255 mins ago 0xe3ffc583dc176575eea7fd9df2a7c65f7e23f4c3 Wrapped AVAX15 AVAX
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LBRouter

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 25 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 2 of 25 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 3 of 25 : LBErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./interfaces/ILBPair.sol";

/** LBRouter errors */

error LBRouter__SenderIsNotWAVAX();
error LBRouter__PairNotCreated(address tokenX, address tokenY, uint256 binStep);
error LBRouter__WrongAmounts(uint256 amount, uint256 reserve);
error LBRouter__SwapOverflows(uint256 id);
error LBRouter__BrokenSwapSafetyCheck();
error LBRouter__NotFactoryOwner();
error LBRouter__TooMuchTokensIn(uint256 excess);
error LBRouter__BinReserveOverflows(uint256 id);
error LBRouter__IdOverflows(int256 id);
error LBRouter__LengthsMismatch();
error LBRouter__WrongTokenOrder();
error LBRouter__IdSlippageCaught(uint256 activeIdDesired, uint256 idSlippage, uint256 activeId);
error LBRouter__AmountSlippageCaught(uint256 amountXMin, uint256 amountX, uint256 amountYMin, uint256 amountY);
error LBRouter__IdDesiredOverflows(uint256 idDesired, uint256 idSlippage);
error LBRouter__FailedToSendAVAX(address recipient, uint256 amount);
error LBRouter__DeadlineExceeded(uint256 deadline, uint256 currentTimestamp);
error LBRouter__AmountSlippageBPTooBig(uint256 amountSlippage);
error LBRouter__InsufficientAmountOut(uint256 amountOutMin, uint256 amountOut);
error LBRouter__MaxAmountInExceeded(uint256 amountInMax, uint256 amountIn);
error LBRouter__InvalidTokenPath(address wrongToken);
error LBRouter__InvalidVersion(uint256 version);
error LBRouter__WrongAvaxLiquidityParameters(
    address tokenX,
    address tokenY,
    uint256 amountX,
    uint256 amountY,
    uint256 msgValue
);

/** LBToken errors */

error LBToken__SpenderNotApproved(address owner, address spender);
error LBToken__TransferFromOrToAddress0();
error LBToken__MintToAddress0();
error LBToken__BurnFromAddress0();
error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__LengthMismatch(uint256 accountsLength, uint256 idsLength);
error LBToken__SelfApproval(address owner);
error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__TransferToSelf();

/** LBFactory errors */

error LBFactory__IdenticalAddresses(IERC20 token);
error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset);
error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset);
error LBFactory__AddressZero();
error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep);
error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__DecreasingPeriods(uint16 filterPeriod, uint16 decayPeriod);
error LBFactory__ReductionFactorOverflows(uint16 reductionFactor, uint256 max);
error LBFactory__VariableFeeControlOverflows(uint16 variableFeeControl, uint256 max);
error LBFactory__BaseFeesBelowMin(uint256 baseFees, uint256 minBaseFees);
error LBFactory__FeesAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__BinStepRequirementsBreached(uint256 lowerBound, uint16 binStep, uint256 higherBound);
error LBFactory__ProtocolShareOverflows(uint16 protocolShare, uint256 max);
error LBFactory__FunctionIsLockedForUsers(address user);
error LBFactory__FactoryLockIsAlreadyInTheSameState();
error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
error LBFactory__BinStepHasNoPreset(uint256 binStep);
error LBFactory__SameFeeRecipient(address feeRecipient);
error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
error LBFactory__SameImplementation(address LBPairImplementation);
error LBFactory__ImplementationNotSet();

/** LBPair errors */

error LBPair__InsufficientAmounts();
error LBPair__AddressZero();
error LBPair__AddressZeroOrThis();
error LBPair__CompositionFactorFlawed(uint256 id);
error LBPair__InsufficientLiquidityMinted(uint256 id);
error LBPair__InsufficientLiquidityBurned(uint256 id);
error LBPair__WrongLengths();
error LBPair__OnlyStrictlyIncreasingId();
error LBPair__OnlyFactory();
error LBPair__DistributionsOverflow();
error LBPair__OnlyFeeRecipient(address feeRecipient, address sender);
error LBPair__OracleNotEnoughSample();
error LBPair__AlreadyInitialized();
error LBPair__OracleNewSizeTooSmall(uint256 newSize, uint256 oracleSize);
error LBPair__FlashLoanCallbackFailed();
error LBPair__FlashLoanInvalidBalance();
error LBPair__FlashLoanInvalidToken();

/** BinHelper errors */

error BinHelper__BinStepOverflows(uint256 bp);
error BinHelper__IdOverflows();

/** Math128x128 errors */

error Math128x128__PowerUnderflow(uint256 x, int256 y);
error Math128x128__LogUnderflow();

/** Math512Bits errors */

error Math512Bits__MulDivOverflow(uint256 prod1, uint256 denominator);
error Math512Bits__ShiftDivOverflow(uint256 prod1, uint256 denominator);
error Math512Bits__MulShiftOverflow(uint256 prod1, uint256 offset);
error Math512Bits__OffsetOverflows(uint256 offset);

/** Oracle errors */

error Oracle__AlreadyInitialized(uint256 _index);
error Oracle__LookUpTimestampTooOld(uint256 _minTimestamp, uint256 _lookUpTimestamp);
error Oracle__NotInitialized();

/** PendingOwnable errors */

error PendingOwnable__NotOwner();
error PendingOwnable__NotPendingOwner();
error PendingOwnable__PendingOwnerAlreadySet();
error PendingOwnable__NoPendingOwner();
error PendingOwnable__AddressZero();

/** ReentrancyGuardUpgradeable errors */

error ReentrancyGuardUpgradeable__ReentrantCall();
error ReentrancyGuardUpgradeable__AlreadyInitialized();

/** SafeCast errors */

error SafeCast__Exceeds256Bits(uint256 x);
error SafeCast__Exceeds248Bits(uint256 x);
error SafeCast__Exceeds240Bits(uint256 x);
error SafeCast__Exceeds232Bits(uint256 x);
error SafeCast__Exceeds224Bits(uint256 x);
error SafeCast__Exceeds216Bits(uint256 x);
error SafeCast__Exceeds208Bits(uint256 x);
error SafeCast__Exceeds200Bits(uint256 x);
error SafeCast__Exceeds192Bits(uint256 x);
error SafeCast__Exceeds184Bits(uint256 x);
error SafeCast__Exceeds176Bits(uint256 x);
error SafeCast__Exceeds168Bits(uint256 x);
error SafeCast__Exceeds160Bits(uint256 x);
error SafeCast__Exceeds152Bits(uint256 x);
error SafeCast__Exceeds144Bits(uint256 x);
error SafeCast__Exceeds136Bits(uint256 x);
error SafeCast__Exceeds128Bits(uint256 x);
error SafeCast__Exceeds120Bits(uint256 x);
error SafeCast__Exceeds112Bits(uint256 x);
error SafeCast__Exceeds104Bits(uint256 x);
error SafeCast__Exceeds96Bits(uint256 x);
error SafeCast__Exceeds88Bits(uint256 x);
error SafeCast__Exceeds80Bits(uint256 x);
error SafeCast__Exceeds72Bits(uint256 x);
error SafeCast__Exceeds64Bits(uint256 x);
error SafeCast__Exceeds56Bits(uint256 x);
error SafeCast__Exceeds48Bits(uint256 x);
error SafeCast__Exceeds40Bits(uint256 x);
error SafeCast__Exceeds32Bits(uint256 x);
error SafeCast__Exceeds24Bits(uint256 x);
error SafeCast__Exceeds16Bits(uint256 x);
error SafeCast__Exceeds8Bits(uint256 x);

/** TreeMath errors */

error TreeMath__ErrorDepthSearch();

/** JoeLibrary errors */

error JoeLibrary__IdenticalAddresses();
error JoeLibrary__AddressZero();
error JoeLibrary__InsufficientAmount();
error JoeLibrary__InsufficientLiquidity();

/** TokenHelper errors */

error TokenHelper__NonContract();
error TokenHelper__CallFailed();
error TokenHelper__TransferFailed();

/** LBQuoter errors */

error LBQuoter_InvalidLength();

File 4 of 25 : LBRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "./LBErrors.sol";
import "./libraries/BinHelper.sol";
import "./libraries/Constants.sol";
import "./libraries/FeeHelper.sol";
import "./libraries/JoeLibrary.sol";
import "./libraries/Math512Bits.sol";
import "./libraries/SwapHelper.sol";
import "./libraries/TokenHelper.sol";
import "./interfaces/IJoePair.sol";
import "./interfaces/ILBToken.sol";
import "./interfaces/ILBRouter.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 TokenHelper for IWAVAX;
    using FeeHelper for FeeHelper.FeeParameters;
    using Math512Bits for uint256;
    using SwapHelper for ILBPair.Bin;
    using JoeLibrary for uint256;

    ILBFactory public immutable override factory;
    IJoeFactory public immutable override oldFactory;
    IWAVAX public immutable override wavax;

    modifier onlyFactoryOwner() {
        if (msg.sender != factory.owner()) revert LBRouter__NotFactoryOwner();
        _;
    }

    modifier ensure(uint256 _deadline) {
        if (block.timestamp > _deadline) revert LBRouter__DeadlineExceeded(_deadline, block.timestamp);
        _;
    }

    modifier verifyInputs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) {
        if (_pairBinSteps.length == 0 || _pairBinSteps.length + 1 != _tokenPath.length)
            revert LBRouter__LengthsMismatch();
        _;
    }

    /// @notice Constructor
    /// @param _factory LBFactory address
    /// @param _oldFactory Address of old factory (Joe V1)
    /// @param _wavax Address of WAVAX
    constructor(
        ILBFactory _factory,
        IJoeFactory _oldFactory,
        IWAVAX _wavax
    ) {
        factory = _factory;
        oldFactory = _oldFactory;
        wavax = _wavax;
    }

    /// @dev Receive function that only accept AVAX from the WAVAX contract
    receive() external payable {
        if (msg.sender != address(wavax)) revert LBRouter__SenderIsNotWAVAX();
    }

    /// @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 _LBPair 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 _LBPair, uint256 _price) external view override returns (uint24) {
        return BinHelper.getIdFromPrice(_price, _LBPair.feeParameters().binStep);
    }

    /// @notice Returns the price corresponding to the inputted id
    /// @param _LBPair The address of the LBPair
    /// @param _id The id
    /// @return The price corresponding to this id
    function getPriceFromId(ILBPair _LBPair, uint24 _id) external view override returns (uint256) {
        return BinHelper.getPriceFromId(_id, _LBPair.feeParameters().binStep);
    }

    /// @notice Simulate a swap in
    /// @param _LBPair 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 feesIn The amount of fees paid in token sent
    function getSwapIn(
        ILBPair _LBPair,
        uint256 _amountOut,
        bool _swapForY
    ) public view override returns (uint256 amountIn, uint256 feesIn) {
        (uint256 _pairReserveX, uint256 _pairReserveY, uint256 _activeId) = _LBPair.getReservesAndId();

        if (_amountOut == 0 || (_swapForY ? _amountOut > _pairReserveY : _amountOut > _pairReserveX))
            revert LBRouter__WrongAmounts(_amountOut, _swapForY ? _pairReserveY : _pairReserveX); // If this is wrong, then we're sure the amounts sent are wrong

        FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters();
        _fp.updateVariableFeeParameters(_activeId);

        uint256 _amountOutOfBin;
        uint256 _amountInWithFees;
        uint256 _reserve;
        // Performs the actual swap, bin per bin
        // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at
        // has liquidity in it.
        while (true) {
            {
                (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId));
                _reserve = _swapForY ? _reserveY : _reserveX;
            }
            uint256 _price = BinHelper.getPriceFromId(_activeId, _fp.binStep);
            if (_reserve != 0) {
                _amountOutOfBin = _amountOut >= _reserve ? _reserve : _amountOut;
                uint256 _amountInToBin = _swapForY
                    ? _amountOutOfBin.shiftDivRoundUp(Constants.SCALE_OFFSET, _price)
                    : _price.mulShiftRoundUp(_amountOutOfBin, Constants.SCALE_OFFSET);

                // We update the fee, but we don't store the new volatility reference, volatility accumulated and indexRef to not penalize traders
                _fp.updateVolatilityAccumulated(_activeId);
                uint256 _fee = _fp.getFeeAmount(_amountInToBin);
                _amountInWithFees = _amountInToBin + _fee;

                if (_amountInWithFees + _reserve > type(uint112).max) revert LBRouter__SwapOverflows(_activeId);
                amountIn += _amountInWithFees;
                feesIn += _fee;
                _amountOut -= _amountOutOfBin;
            }

            if (_amountOut != 0) {
                _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY);
            } else {
                break;
            }
        }
        if (_amountOut != 0) revert LBRouter__BrokenSwapSafetyCheck(); // Safety check, but should never be false as it would have reverted on transfer
    }

    /// @notice Simulate a swap out
    /// @param _LBPair 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 amountOut The amount of token received if _amountIn tokenX are sent
    /// @return feesIn The amount of fees paid in token sent
    function getSwapOut(
        ILBPair _LBPair,
        uint256 _amountIn,
        bool _swapForY
    ) external view override returns (uint256 amountOut, uint256 feesIn) {
        (, , uint256 _activeId) = _LBPair.getReservesAndId();

        FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters();
        _fp.updateVariableFeeParameters(_activeId);
        ILBPair.Bin memory _bin;

        // Performs the actual swap, bin per bin
        // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at
        // has liquidity in it.
        while (true) {
            {
                (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId));
                _bin = ILBPair.Bin(uint112(_reserveX), uint112(_reserveY), 0, 0);
            }
            if (_bin.reserveX != 0 || _bin.reserveY != 0) {
                (uint256 _amountInToBin, uint256 _amountOutOfBin, FeeHelper.FeesDistribution memory _fees) = _bin
                    .getAmounts(_fp, _activeId, _swapForY, _amountIn);

                if (_amountInToBin > type(uint112).max) revert LBRouter__BinReserveOverflows(_activeId);

                _amountIn -= _amountInToBin + _fees.total;
                feesIn += _fees.total;
                amountOut += _amountOutOfBin;
            }

            if (_amountIn != 0) {
                _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY);
            } else {
                break;
            }
        }
        if (_amountIn != 0) revert LBRouter__TooMuchTokensIn(_amountIn);
    }

    /// @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 = factory.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 depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function addLiquidity(LiquidityParameters calldata _liquidityParameters)
        external
        override
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
    {
        ILBPair _LBPair = _getLBPairInformation(
            _liquidityParameters.tokenX,
            _liquidityParameters.tokenY,
            _liquidityParameters.binStep
        );
        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();

        _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX);
        _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY);

        (depositIds, liquidityMinted) = _addLiquidity(_liquidityParameters, _LBPair);
    }

    /// @notice Add liquidity with AVAX while performing safety checks
    /// @dev This function is compliant with fee on transfer tokens
    /// @param _liquidityParameters The liquidity parameters
    /// @return depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function addLiquidityAVAX(LiquidityParameters calldata _liquidityParameters)
        external
        payable
        override
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted)
    {
        ILBPair _LBPair = _getLBPairInformation(
            _liquidityParameters.tokenX,
            _liquidityParameters.tokenY,
            _liquidityParameters.binStep
        );
        if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder();

        if (_liquidityParameters.tokenX == wavax && _liquidityParameters.amountX == msg.value) {
            _wavaxDepositAndTransfer(address(_LBPair), msg.value);
            _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY);
        } else if (_liquidityParameters.tokenY == wavax && _liquidityParameters.amountY == msg.value) {
            _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX);
            _wavaxDepositAndTransfer(address(_LBPair), msg.value);
        } else
            revert LBRouter__WrongAvaxLiquidityParameters(
                address(_liquidityParameters.tokenX),
                address(_liquidityParameters.tokenY),
                _liquidityParameters.amountX,
                _liquidityParameters.amountY,
                msg.value
            );

        (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 = _getLBPairInformation(_tokenX, _tokenY, _binStep);
        bool _isWrongOrder = _tokenX != _LBPair.tokenX();

        if (_isWrongOrder) (_amountXMin, _amountYMin) = (_amountYMin, _amountXMin);

        (amountX, amountY) = _removeLiquidity(_LBPair, _amountXMin, _amountYMin, _ids, _amounts, _to);

        if (_isWrongOrder) (amountX, amountY) = (amountY, amountX);
    }

    /// @notice Remove AVAX 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 _amountAVAXMin The min amount to receive of AVAX
    /// @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 amountAVAX Amount of AVAX returned
    function removeLiquidityAVAX(
        IERC20 _token,
        uint16 _binStep,
        uint256 _amountTokenMin,
        uint256 _amountAVAXMin,
        uint256[] memory _ids,
        uint256[] memory _amounts,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) returns (uint256 amountToken, uint256 amountAVAX) {
        ILBPair _LBPair = _getLBPairInformation(_token, IERC20(wavax), _binStep);

        bool _isAVAXTokenY = IERC20(wavax) == _LBPair.tokenY();
        {
            if (!_isAVAXTokenY) {
                (_amountTokenMin, _amountAVAXMin) = (_amountAVAXMin, _amountTokenMin);
            }

            (uint256 _amountX, uint256 _amountY) = _removeLiquidity(
                _LBPair,
                _amountTokenMin,
                _amountAVAXMin,
                _ids,
                _amounts,
                address(this)
            );

            (amountToken, amountAVAX) = _isAVAXTokenY ? (_amountX, _amountY) : (_amountY, _amountX);
        }

        _token.safeTransfer(_to, amountToken);

        wavax.withdraw(amountAVAX);
        _safeTransferAVAX(_to, amountAVAX);
    }

    /// @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 _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @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,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, _to);

        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Swaps exact tokens for AVAX while performing safety checks
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMinAVAX The min amount of AVAX to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForAVAX(
        uint256 _amountIn,
        uint256 _amountOutMinAVAX,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, address(this));

        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);

        wavax.withdraw(amountOut);
        _safeTransferAVAX(_to, amountOut);
    }

    /// @notice Swaps exact AVAX for tokens while performing safety checks
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactAVAXForTokens(
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        _wavaxDepositAndTransfer(_pairs[0], msg.value);

        amountOut = _swapExactTokensForTokens(msg.value, _pairs, _pairBinSteps, _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 _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapTokensForExactTokens(
        uint256 _amountOut,
        uint256 _amountInMax,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);

        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);

        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);
    }

    /// @notice Swaps tokens for exact AVAX while performing safety checks
    /// @param _amountAVAXOut The amount of AVAX to receive
    /// @param _amountInMax The max amount of token to send
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapTokensForExactAVAX(
        uint256 _amountAVAXOut,
        uint256 _amountInMax,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountAVAXOut);

        if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, address(this));

        if (_amountOutReal < _amountAVAXOut) revert LBRouter__InsufficientAmountOut(_amountAVAXOut, _amountOutReal);

        wavax.withdraw(_amountOutReal);
        _safeTransferAVAX(_to, _amountOutReal);
    }

    /// @notice Swaps AVAX for exact tokens while performing safety checks
    /// @dev Will refund any AVAX amount sent in excess to `msg.sender`
    /// @param _amountOut The amount of tokens to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountsIn Input amounts for every step of the swap
    function swapAVAXForExactTokens(
        uint256 _amountOut,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    )
        external
        payable
        override
        ensure(_deadline)
        verifyInputs(_pairBinSteps, _tokenPath)
        returns (uint256[] memory amountsIn)
    {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);
        amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut);

        if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);

        _wavaxDepositAndTransfer(_pairs[0], amountsIn[0]);

        uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to);

        if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal);

        if (msg.value > amountsIn[0]) _safeTransferAVAX(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 _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @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,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        IERC20 _targetToken = _tokenPath[_pairs.length];

        uint256 _balanceBefore = _targetToken.balanceOf(_to);

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to);

        amountOut = _targetToken.balanceOf(_to) - _balanceBefore;
        if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut);
    }

    /// @notice Swaps exact tokens for AVAX while performing safety checks supporting for fee on transfer tokens
    /// @param _amountIn The amount of token to send
    /// @param _amountOutMinAVAX The min amount of AVAX to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactTokensForAVAXSupportingFeeOnTransferTokens(
        uint256 _amountIn,
        uint256 _amountOutMinAVAX,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address payable _to,
        uint256 _deadline
    ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[_pairBinSteps.length] != IERC20(wavax))
            revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        uint256 _balanceBefore = wavax.balanceOf(address(this));

        _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, address(this));

        amountOut = wavax.balanceOf(address(this)) - _balanceBefore;
        if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut);

        wavax.withdraw(amountOut);
        _safeTransferAVAX(_to, amountOut);
    }

    /// @notice Swaps exact AVAX for tokens while performing safety checks supporting for fee on transfer tokens
    /// @param _amountOutMin The min amount of token to receive
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    /// @param _deadline The deadline of the tx
    /// @return amountOut Output amount of the swap
    function swapExactAVAXForTokensSupportingFeeOnTransferTokens(
        uint256 _amountOutMin,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to,
        uint256 _deadline
    ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) {
        if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0]));

        address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath);

        IERC20 _targetToken = _tokenPath[_pairs.length];

        uint256 _balanceBefore = _targetToken.balanceOf(_to);

        _wavaxDepositAndTransfer(_pairs[0], msg.value);

        _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _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)) {
            if (_amount == type(uint256).max) _amount = address(this).balance;
            _safeTransferAVAX(_to, _amount);
        } else {
            if (_amount == type(uint256).max) _amount = _token.balanceOf(address(this));
            _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.safeBatchTransferFrom(address(this), _to, _ids, _amounts);
    }

    /// @notice Helper function to add liquidity
    /// @param _liq The liquidity parameter
    /// @param _LBPair LBPair where liquidity is deposited
    /// @return depositIds Bin ids where the liquidity was actually deposited
    /// @return liquidityMinted Amounts of LBToken minted for each bin
    function _addLiquidity(LiquidityParameters calldata _liq, ILBPair _LBPair)
        private
        ensure(_liq.deadline)
        returns (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);

            (, , uint256 _activeId) = _LBPair.getReservesAndId();
            if (
                _liq.activeIdDesired + _liq.idSlippage < _activeId || _activeId + _liq.idSlippage < _liq.activeIdDesired
            ) revert LBRouter__IdSlippageCaught(_liq.activeIdDesired, _liq.idSlippage, _activeId);

            depositIds = new uint256[](_liq.deltaIds.length);
            for (uint256 i; i < depositIds.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);
            }

            uint256 _amountXAdded;
            uint256 _amountYAdded;

            (_amountXAdded, _amountYAdded, liquidityMinted) = _LBPair.mint(
                depositIds,
                _liq.distributionX,
                _liq.distributionY,
                _liq.to
            );

            if (_amountXAdded < _liq.amountXMin || _amountYAdded < _liq.amountYMin)
                revert LBRouter__AmountSlippageCaught(_liq.amountXMin, _amountXAdded, _liq.amountYMin, _amountYAdded);
        }
    }

    /// @notice Helper function to return the amounts in
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @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(
        uint256[] memory _pairBinSteps,
        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];
            uint256 _binStep = _pairBinSteps[i - 1];

            address _pair = _pairs[i - 1];

            if (_binStep == 0) {
                (uint256 _reserveIn, uint256 _reserveOut, ) = IJoePair(_pair).getReserves();
                if (_token > _tokenPath[i]) {
                    (_reserveIn, _reserveOut) = (_reserveOut, _reserveIn);
                }

                uint256 amountOut_ = amountsIn[i];
                amountsIn[i - 1] = amountOut_.getAmountIn(_reserveIn, _reserveOut);
            } else {
                (amountsIn[i - 1], ) = getSwapIn(ILBPair(_pair), amountsIn[i], ILBPair(_pair).tokenX() == _token);
            }
        }
    }

    /// @notice Helper function to remove liquidity
    /// @param _LBPair 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 _LBPair,
        uint256 _amountXMin,
        uint256 _amountYMin,
        uint256[] memory _ids,
        uint256[] memory _amounts,
        address _to
    ) private returns (uint256 amountX, uint256 amountY) {
        ILBToken(address(_LBPair)).safeBatchTransferFrom(msg.sender, address(_LBPair), _ids, _amounts);
        (amountX, amountY) = _LBPair.burn(_ids, _amounts, _to);
        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 _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @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,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to
    ) private returns (uint256 amountOut) {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];
        amountOut = _amountIn;

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    (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 {
                    bool _swapForY = _tokenNext == ILBPair(_pair).tokenY();

                    (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient);

                    if (_swapForY) amountOut = _amountYOut;
                    else amountOut = _amountXOut;
                }
            }
        }
    }

    /// @notice Helper function to swap tokens for exact tokens
    /// @param _pairs The array of pairs
    /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @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,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        uint256[] memory _amountsIn,
        address _to
    ) private returns (uint256 amountOut) {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    amountOut = _amountsIn[i + 1];
                    if (_token < _tokenNext) {
                        IJoePair(_pair).swap(0, amountOut, _recipient, "");
                    } else {
                        IJoePair(_pair).swap(amountOut, 0, _recipient, "");
                    }
                } else {
                    bool _swapForY = _tokenNext == ILBPair(_pair).tokenY();

                    (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient);

                    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 _pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
    /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps`
    /// @param _to The address of the recipient
    function _swapSupportingFeeOnTransferTokens(
        address[] memory _pairs,
        uint256[] memory _pairBinSteps,
        IERC20[] memory _tokenPath,
        address _to
    ) private {
        IERC20 _token;
        uint256 _binStep;
        address _recipient;
        address _pair;

        IERC20 _tokenNext = _tokenPath[0];

        unchecked {
            for (uint256 i; i < _pairs.length; ++i) {
                _pair = _pairs[i];
                _binStep = _pairBinSteps[i];

                _token = _tokenNext;
                _tokenNext = _tokenPath[i + 1];

                _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1];

                if (_binStep == 0) {
                    (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 {
                    ILBPair(_pair).swap(_tokenNext == ILBPair(_pair).tokenY(), _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
    /// @return The address of the LBPair
    function _getLBPairInformation(
        IERC20 _tokenX,
        IERC20 _tokenY,
        uint256 _binStep
    ) private view returns (ILBPair) {
        ILBPair _LBPair = factory.getLBPairInformation(_tokenX, _tokenY, _binStep).LBPair;
        if (address(_LBPair) == address(0))
            revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep);
        return _LBPair;
    }

    /// @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 _binStep The bin step of the LBPair, 0 means using V1 pair, any other value will use V2
    /// @param _tokenX The address of the tokenX
    /// @param _tokenY The address of the tokenY
    /// @return _pair The address of the pair of binStep `_binStep`
    function _getPair(
        uint256 _binStep,
        IERC20 _tokenX,
        IERC20 _tokenY
    ) private view returns (address _pair) {
        if (_binStep == 0) {
            _pair = oldFactory.getPair(address(_tokenX), address(_tokenY));
            if (_pair == address(0)) revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep);
        } else _pair = address(_getLBPairInformation(_tokenX, _tokenY, _binStep));
    }

    function _getPairs(uint256[] memory _pairBinSteps, 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(_pairBinSteps[i], _token, _tokenNext);
            }
        }
    }

    /// @notice Helper function to transfer AVAX
    /// @param _to The address of the recipient
    /// @param _amount The AVAX amount to send
    function _safeTransferAVAX(address _to, uint256 _amount) private {
        (bool success, ) = _to.call{value: _amount}("");
        if (!success) revert LBRouter__FailedToSendAVAX(_to, _amount);
    }

    /// @notice Helper function to deposit and transfer wavax
    /// @param _to The address of the recipient
    /// @param _amount The AVAX amount to wrap
    function _wavaxDepositAndTransfer(address _to, uint256 _amount) private {
        wavax.deposit{value: _amount}();
        wavax.safeTransfer(_to, _amount);
    }
}

File 5 of 25 : IJoeFactory.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

/// @title Joe V1 Factory Interface
/// @notice Interface to interact with Joe V1 Factory
interface IJoeFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);

    function feeTo() external view returns (address);

    function feeToSetter() external view returns (address);

    function migrator() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);

    function allPairs(uint256) external view returns (address pair);

    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;

    function setFeeToSetter(address) external;

    function setMigrator(address) external;
}

File 6 of 25 : IJoePair.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

/// @title Joe V1 Pair Interface
/// @notice Interface to interact with Joe V1 Pairs
interface IJoePair {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function name() external pure returns (string memory);

    function symbol() external pure returns (string memory);

    function decimals() external pure returns (uint8);

    function totalSupply() external view returns (uint256);

    function balanceOf(address owner) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transfer(address to, uint256 value) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function PERMIT_TYPEHASH() external pure returns (bytes32);

    function nonces(address owner) external view returns (uint256);

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint256);

    function factory() external view returns (address);

    function token0() external view returns (address);

    function token1() external view returns (address);

    function getReserves()
        external
        view
        returns (
            uint112 reserve0,
            uint112 reserve1,
            uint32 blockTimestampLast
        );

    function price0CumulativeLast() external view returns (uint256);

    function price1CumulativeLast() external view returns (uint256);

    function kLast() external view returns (uint256);

    function mint(address to) external returns (uint256 liquidity);

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function skim(address to) external;

    function sync() external;

    function initialize(address, address) external;
}

File 7 of 25 : ILBFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "./ILBPair.sol";
import "./IPendingOwnable.sol";

/// @title Liquidity Book Factory Interface
/// @author Trader Joe
/// @notice Required interface of LBFactory contract
interface ILBFactory is IPendingOwnable {
    /// @dev Structure to store the LBPair information, such as:
    /// - binStep: The bin step of the LBPair
    /// - LBPair: The address of the LBPair
    /// - createdByOwner: Whether the pair was created by the owner of the factory
    /// - ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding
    struct LBPairInformation {
        uint16 binStep;
        ILBPair LBPair;
        bool createdByOwner;
        bool ignoredForRouting;
    }

    event LBPairCreated(
        IERC20 indexed tokenX,
        IERC20 indexed tokenY,
        uint256 indexed binStep,
        ILBPair LBPair,
        uint256 pid
    );

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);

    event FeeParametersSet(
        address indexed sender,
        ILBPair indexed LBPair,
        uint256 binStep,
        uint256 baseFactor,
        uint256 filterPeriod,
        uint256 decayPeriod,
        uint256 reductionFactor,
        uint256 variableFeeControl,
        uint256 protocolShare,
        uint256 maxVolatilityAccumulated
    );

    event FactoryLockedStatusUpdated(bool unlocked);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);

    event PresetSet(
        uint256 indexed binStep,
        uint256 baseFactor,
        uint256 filterPeriod,
        uint256 decayPeriod,
        uint256 reductionFactor,
        uint256 variableFeeControl,
        uint256 protocolShare,
        uint256 maxVolatilityAccumulated,
        uint256 sampleLifetime
    );

    event PresetRemoved(uint256 indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function MAX_FEE() external pure returns (uint256);

    function MIN_BIN_STEP() external pure returns (uint256);

    function MAX_BIN_STEP() external pure returns (uint256);

    function MAX_PROTOCOL_SHARE() external pure returns (uint256);

    function LBPairImplementation() external view returns (address);

    function getNumberOfQuoteAssets() external view returns (uint256);

    function getQuoteAsset(uint256 index) external view returns (IERC20);

    function isQuoteAsset(IERC20 token) external view returns (bool);

    function feeRecipient() external view returns (address);

    function flashLoanFee() external view returns (uint256);

    function creationUnlocked() external view returns (bool);

    function allLBPairs(uint256 id) external returns (ILBPair);

    function getNumberOfLBPairs() external view returns (uint256);

    function getLBPairInformation(
        IERC20 tokenX,
        IERC20 tokenY,
        uint256 binStep
    ) external view returns (LBPairInformation memory);

    function getPreset(uint16 binStep)
        external
        view
        returns (
            uint256 baseFactor,
            uint256 filterPeriod,
            uint256 decayPeriod,
            uint256 reductionFactor,
            uint256 variableFeeControl,
            uint256 protocolShare,
            uint256 maxAccumulator,
            uint256 sampleLifetime
        );

    function getAllBinSteps() external view returns (uint256[] memory presetsBinStep);

    function getAllLBPairs(IERC20 tokenX, IERC20 tokenY)
        external
        view
        returns (LBPairInformation[] memory LBPairsBinStep);

    function setLBPairImplementation(address LBPairImplementation) external;

    function createLBPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint24 activeId,
        uint16 binStep
    ) external returns (ILBPair pair);

    function setLBPairIgnored(
        IERC20 tokenX,
        IERC20 tokenY,
        uint256 binStep,
        bool ignored
    ) external;

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulated,
        uint16 sampleLifetime
    ) external;

    function removePreset(uint16 binStep) external;

    function setFeesParametersOnPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulated
    ) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint256 flashLoanFee) external;

    function setFactoryLockedState(bool locked) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair LBPair) external;
}

File 8 of 25 : ILBFlashLoanCallback.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

/// @title Liquidity Book Flashloan Callback Interface
/// @author Trader Joe
/// @notice Required interface to interact with LB flash loans
interface ILBFlashLoanCallback {
    function LBFlashLoanCallback(
        address sender,
        IERC20 token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}

File 9 of 25 : ILBPair.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "../libraries/FeeHelper.sol";
import "./ILBFactory.sol";
import "./ILBFlashLoanCallback.sol";

/// @title Liquidity Book Pair Interface
/// @author Trader Joe
/// @notice Required interface of LBPair contract
interface ILBPair {
    /// @dev Structure to store the reserves of bins:
    /// - reserveX: The current reserve of tokenX of the bin
    /// - reserveY: The current reserve of tokenY of the bin
    struct Bin {
        uint112 reserveX;
        uint112 reserveY;
        uint256 accTokenXPerShare;
        uint256 accTokenYPerShare;
    }

    /// @dev Structure to store the information of the pair such as:
    /// slot0:
    /// - activeId: The current id used for swaps, this is also linked with the price
    /// - reserveX: The sum of amounts of tokenX across all bins
    /// slot1:
    /// - reserveY: The sum of amounts of tokenY across all bins
    /// - oracleSampleLifetime: The lifetime of an oracle sample
    /// - oracleSize: The current size of the oracle, can be increase by users
    /// - oracleActiveSize: The current active size of the oracle, composed only from non empty data sample
    /// - oracleLastTimestamp: The current last timestamp at which a sample was added to the circular buffer
    /// - oracleId: The current id of the oracle
    /// slot2:
    /// - feesX: The current amount of fees to distribute in tokenX (total, protocol)
    /// slot3:
    /// - feesY: The current amount of fees to distribute in tokenY (total, protocol)
    struct PairInformation {
        uint24 activeId;
        uint136 reserveX;
        uint136 reserveY;
        uint16 oracleSampleLifetime;
        uint16 oracleSize;
        uint16 oracleActiveSize;
        uint40 oracleLastTimestamp;
        uint16 oracleId;
        FeeHelper.FeesDistribution feesX;
        FeeHelper.FeesDistribution feesY;
    }

    /// @dev Structure to store the debts of users
    /// - debtX: The tokenX's debt
    /// - debtY: The tokenY's debt
    struct Debts {
        uint256 debtX;
        uint256 debtY;
    }

    /// @dev Structure to store fees:
    /// - tokenX: The amount of fees of token X
    /// - tokenY: The amount of fees of token Y
    struct Fees {
        uint128 tokenX;
        uint128 tokenY;
    }

    /// @dev Structure to minting informations:
    /// - amountXIn: The amount of token X sent
    /// - amountYIn: The amount of token Y sent
    /// - amountXAddedToPair: The amount of token X that have been actually added to the pair
    /// - amountYAddedToPair: The amount of token Y that have been actually added to the pair
    /// - activeFeeX: Fees X currently generated
    /// - activeFeeY: Fees Y currently generated
    /// - totalDistributionX: Total distribution of token X. Should be 1e18 (100%) or 0 (0%)
    /// - totalDistributionY: Total distribution of token Y. Should be 1e18 (100%) or 0 (0%)
    /// - id: Id of the current working bin when looping on the distribution array
    /// - amountX: The amount of token X deposited in the current bin
    /// - amountY: The amount of token Y deposited in the current bin
    /// - distributionX: Distribution of token X for the current working bin
    /// - distributionY: Distribution of token Y for the current working bin
    struct MintInfo {
        uint256 amountXIn;
        uint256 amountYIn;
        uint256 amountXAddedToPair;
        uint256 amountYAddedToPair;
        uint256 activeFeeX;
        uint256 activeFeeY;
        uint256 totalDistributionX;
        uint256 totalDistributionY;
        uint256 id;
        uint256 amountX;
        uint256 amountY;
        uint256 distributionX;
        uint256 distributionY;
    }

    event Swap(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        bool swapForY,
        uint256 amountIn,
        uint256 amountOut,
        uint256 volatilityAccumulated,
        uint256 fees
    );

    event FlashLoan(
        address indexed sender,
        ILBFlashLoanCallback indexed receiver,
        IERC20 token,
        uint256 amount,
        uint256 fee
    );

    event CompositionFee(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 feesX,
        uint256 feesY
    );

    event DepositedToBin(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 amountX,
        uint256 amountY
    );

    event WithdrawnFromBin(
        address indexed sender,
        address indexed recipient,
        uint256 indexed id,
        uint256 amountX,
        uint256 amountY
    );

    event FeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY);

    event ProtocolFeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY);

    event OracleSizeIncreased(uint256 previousSize, uint256 newSize);

    function tokenX() external view returns (IERC20);

    function tokenY() external view returns (IERC20);

    function factory() external view returns (ILBFactory);

    function getReservesAndId()
        external
        view
        returns (
            uint256 reserveX,
            uint256 reserveY,
            uint256 activeId
        );

    function getGlobalFees()
        external
        view
        returns (
            uint128 feesXTotal,
            uint128 feesYTotal,
            uint128 feesXProtocol,
            uint128 feesYProtocol
        );

    function getOracleParameters()
        external
        view
        returns (
            uint256 oracleSampleLifetime,
            uint256 oracleSize,
            uint256 oracleActiveSize,
            uint256 oracleLastTimestamp,
            uint256 oracleId,
            uint256 min,
            uint256 max
        );

    function getOracleSampleFrom(uint256 timeDelta)
        external
        view
        returns (
            uint256 cumulativeId,
            uint256 cumulativeAccumulator,
            uint256 cumulativeBinCrossed
        );

    function feeParameters() external view returns (FeeHelper.FeeParameters memory);

    function findFirstNonEmptyBinId(uint24 id_, bool sentTokenY) external view returns (uint24 id);

    function getBin(uint24 id) external view returns (uint256 reserveX, uint256 reserveY);

    function pendingFees(address account, uint256[] memory ids)
        external
        view
        returns (uint256 amountX, uint256 amountY);

    function swap(bool sentTokenY, address to) external returns (uint256 amountXOut, uint256 amountYOut);

    function flashLoan(
        ILBFlashLoanCallback receiver,
        IERC20 token,
        uint256 amount,
        bytes calldata data
    ) external;

    function mint(
        uint256[] calldata ids,
        uint256[] calldata distributionX,
        uint256[] calldata distributionY,
        address to
    )
        external
        returns (
            uint256 amountXAddedToPair,
            uint256 amountYAddedToPair,
            uint256[] memory liquidityMinted
        );

    function burn(
        uint256[] calldata ids,
        uint256[] calldata amounts,
        address to
    ) external returns (uint256 amountX, uint256 amountY);

    function increaseOracleLength(uint16 newSize) external;

    function collectFees(address account, uint256[] calldata ids) external returns (uint256 amountX, uint256 amountY);

    function collectProtocolFees() external returns (uint128 amountX, uint128 amountY);

    function setFeesParameters(bytes32 packedFeeParameters) external;

    function forceDecay() external;

    function initialize(
        IERC20 tokenX,
        IERC20 tokenY,
        uint24 activeId,
        uint16 sampleLifetime,
        bytes32 packedFeeParameters
    ) external;
}

File 10 of 25 : ILBRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./IJoeFactory.sol";
import "./ILBPair.sol";
import "./ILBToken.sol";
import "./IWAVAX.sol";

/// @title Liquidity Book Router Interface
/// @author Trader Joe
/// @notice Required interface of LBRouter contract
interface ILBRouter {
    /// @dev The liquidity parameters, such as:
    /// - tokenX: The address of token X
    /// - tokenY: The address of token Y
    /// - binStep: The bin step of the pair
    /// - amountX: The amount to send of token X
    /// - amountY: The amount to send of token Y
    /// - amountXMin: The min amount of token X added to liquidity
    /// - amountYMin: The min amount of token Y added to liquidity
    /// - activeIdDesired: The active id that user wants to add liquidity from
    /// - idSlippage: The number of id that are allowed to slip
    /// - deltaIds: The list of delta ids to add liquidity (`deltaId = activeId - desiredId`)
    /// - distributionX: The distribution of tokenX with sum(distributionX) = 100e18 (100%) or 0 (0%)
    /// - distributionY: The distribution of tokenY with sum(distributionY) = 100e18 (100%) or 0 (0%)
    /// - to: The address of the recipient
    /// - deadline: The deadline of the tx
    struct LiquidityParameters {
        IERC20 tokenX;
        IERC20 tokenY;
        uint256 binStep;
        uint256 amountX;
        uint256 amountY;
        uint256 amountXMin;
        uint256 amountYMin;
        uint256 activeIdDesired;
        uint256 idSlippage;
        int256[] deltaIds;
        uint256[] distributionX;
        uint256[] distributionY;
        address to;
        uint256 deadline;
    }

    function factory() external view returns (ILBFactory);

    function oldFactory() external view returns (IJoeFactory);

    function wavax() external view returns (IWAVAX);

    function getIdFromPrice(ILBPair LBPair, uint256 price) external view returns (uint24);

    function getPriceFromId(ILBPair LBPair, uint24 id) external view returns (uint256);

    function getSwapIn(
        ILBPair LBPair,
        uint256 amountOut,
        bool swapForY
    ) external view returns (uint256 amountIn, uint256 feesIn);

    function getSwapOut(
        ILBPair LBPair,
        uint256 amountIn,
        bool swapForY
    ) external view returns (uint256 amountOut, uint256 feesIn);

    function createLBPair(
        IERC20 tokenX,
        IERC20 tokenY,
        uint24 activeId,
        uint16 binStep
    ) external returns (ILBPair pair);

    function addLiquidity(LiquidityParameters calldata liquidityParameters)
        external
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted);

    function addLiquidityAVAX(LiquidityParameters calldata liquidityParameters)
        external
        payable
        returns (uint256[] memory depositIds, uint256[] memory liquidityMinted);

    function removeLiquidity(
        IERC20 tokenX,
        IERC20 tokenY,
        uint16 binStep,
        uint256 amountXMin,
        uint256 amountYMin,
        uint256[] memory ids,
        uint256[] memory amounts,
        address to,
        uint256 deadline
    ) external returns (uint256 amountX, uint256 amountY);

    function removeLiquidityAVAX(
        IERC20 token,
        uint16 binStep,
        uint256 amountTokenMin,
        uint256 amountAVAXMin,
        uint256[] memory ids,
        uint256[] memory amounts,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountAVAX);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactTokensForAVAX(
        uint256 amountIn,
        uint256 amountOutMinAVAX,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactAVAXForTokens(
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountOut);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amountsIn);

    function swapTokensForExactAVAX(
        uint256 amountOut,
        uint256 amountInMax,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256[] memory amountsIn);

    function swapAVAXForExactTokens(
        uint256 amountOut,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amountsIn);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactTokensForAVAXSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMinAVAX,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address payable to,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function swapExactAVAXForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        uint256[] memory pairBinSteps,
        IERC20[] memory tokenPath,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountOut);

    function sweep(
        IERC20 token,
        address to,
        uint256 amount
    ) external;

    function sweepLBToken(
        ILBToken _lbToken,
        address _to,
        uint256[] calldata _ids,
        uint256[] calldata _amounts
    ) external;
}

File 11 of 25 : ILBToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/utils/introspection/IERC165.sol";

/// @title Liquidity Book Token Interface
/// @author Trader Joe
/// @notice Required interface of LBToken contract
interface ILBToken is IERC165 {
    event TransferSingle(address indexed sender, address indexed from, address indexed to, uint256 id, uint256 amount);

    event TransferBatch(
        address indexed sender,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );

    event ApprovalForAll(address indexed account, address indexed sender, bool approved);

    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory batchBalances);

    function totalSupply(uint256 id) external view returns (uint256);

    function isApprovedForAll(address owner, address spender) external view returns (bool);

    function setApprovalForAll(address sender, bool approved) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount
    ) external;

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata id,
        uint256[] calldata amount
    ) external;
}

File 12 of 25 : IPendingOwnable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Pending Ownable Interface
/// @author Trader Joe
/// @notice Required interface of Pending Ownable contract used for LBFactory
interface IPendingOwnable {
    event PendingOwnerSet(address indexed pendingOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function owner() external view returns (address);

    function pendingOwner() external view returns (address);

    function setPendingOwner(address pendingOwner) external;

    function revokePendingOwner() external;

    function becomeOwner() external;

    function renounceOwnership() external;
}

File 13 of 25 : IWAVAX.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

/// @title WAVAX Interface
/// @notice Required interface of Wrapped AVAX contract
interface IWAVAX is IERC20 {
    function deposit() external payable;

    function withdraw(uint256) external;
}

File 14 of 25 : BinHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./Math128x128.sol";

/// @title Liquidity Book Bin Helper Library
/// @author Trader Joe
/// @notice Contract used to convert bin ID to price and back
library BinHelper {
    using Math128x128 for uint256;

    int256 private constant REAL_ID_SHIFT = 1 << 23;

    /// @notice Returns the id corresponding to the given price
    /// @dev The id may be inaccurate due to rounding issues, always trust getPriceFromId rather than
    /// getIdFromPrice
    /// @param _price The price of y per x as a 128.128-binary fixed-point number
    /// @param _binStep The bin step
    /// @return The id corresponding to this price
    function getIdFromPrice(uint256 _price, uint256 _binStep) internal pure returns (uint24) {
        unchecked {
            uint256 _binStepValue = _getBPValue(_binStep);

            // can't overflow as `2**23 + log2(price) < 2**23 + 2**128 < max(uint256)`
            int256 _id = REAL_ID_SHIFT + _price.log2() / _binStepValue.log2();

            if (_id < 0 || uint256(_id) > type(uint24).max) revert BinHelper__IdOverflows();
            return uint24(uint256(_id));
        }
    }

    /// @notice Returns the price corresponding to the given ID, as a 128.128-binary fixed-point number
    /// @dev This is the trusted function to link id to price, the other way may be inaccurate
    /// @param _id The id
    /// @param _binStep The bin step
    /// @return The price corresponding to this id, as a 128.128-binary fixed-point number
    function getPriceFromId(uint256 _id, uint256 _binStep) internal pure returns (uint256) {
        if (_id > uint256(type(uint24).max)) revert BinHelper__IdOverflows();
        unchecked {
            int256 _realId = int256(_id) - REAL_ID_SHIFT;

            return _getBPValue(_binStep).power(_realId);
        }
    }

    /// @notice Returns the (1 + bp) value as a 128.128-decimal fixed-point number
    /// @param _binStep The bp value in [1; 100] (referring to 0.01% to 1%)
    /// @return The (1+bp) value as a 128.128-decimal fixed-point number
    function _getBPValue(uint256 _binStep) internal pure returns (uint256) {
        if (_binStep == 0 || _binStep > Constants.BASIS_POINT_MAX) revert BinHelper__BinStepOverflows(_binStep);

        unchecked {
            // can't overflow as `max(result) = 2**128 + 10_000 << 128 / 10_000 < max(uint256)`
            return Constants.SCALE + (_binStep << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX;
        }
    }
}

File 15 of 25 : BitMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Bit Math Library
/// @author Trader Joe
/// @notice Helper contract used for bit calculations
library BitMath {
    /// @notice Returns the closest non-zero bit of `integer` to the right (of left) of the `bit` bits that is not `bit`
    /// @param _integer The integer as a uint256
    /// @param _bit The bit index
    /// @param _rightSide Whether we're searching in the right side of the tree (true) or the left side (false)
    /// @return The index of the closest non-zero bit. If there is no closest bit, it returns max(uint256)
    function closestBit(
        uint256 _integer,
        uint8 _bit,
        bool _rightSide
    ) internal pure returns (uint256) {
        return _rightSide ? closestBitRight(_integer, _bit - 1) : closestBitLeft(_integer, _bit + 1);
    }

    /// @notice Returns the most (or least) significant bit of `_integer`
    /// @param _integer The integer
    /// @param _isMostSignificant Whether we want the most (true) or the least (false) significant bit
    /// @return The index of the most (or least) significant bit
    function significantBit(uint256 _integer, bool _isMostSignificant) internal pure returns (uint8) {
        return _isMostSignificant ? mostSignificantBit(_integer) : leastSignificantBit(_integer);
    }

    /// @notice Returns the index of the closest bit on the right of x that is non null
    /// @param x The value as a uint256
    /// @param bit The index of the bit to start searching at
    /// @return id The index of the closest non null bit on the right of x.
    /// If there is no closest bit, it returns max(uint256)
    function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) {
        unchecked {
            uint256 _shift = 255 - bit;
            x <<= _shift;

            // can't overflow as it's non-zero and we shifted it by `_shift`
            return (x == 0) ? type(uint256).max : mostSignificantBit(x) - _shift;
        }
    }

    /// @notice Returns the index of the closest bit on the left of x that is non null
    /// @param x The value as a uint256
    /// @param bit The index of the bit to start searching at
    /// @return id The index of the closest non null bit on the left of x.
    /// If there is no closest bit, it returns max(uint256)
    function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) {
        unchecked {
            x >>= bit;

            return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit;
        }
    }

    /// @notice Returns the index of the most significant bit of x
    /// @param x The value as a uint256
    /// @return msb The index of the most significant bit of x
    function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) {
        unchecked {
            if (x >= 1 << 128) {
                x >>= 128;
                msb = 128;
            }
            if (x >= 1 << 64) {
                x >>= 64;
                msb += 64;
            }
            if (x >= 1 << 32) {
                x >>= 32;
                msb += 32;
            }
            if (x >= 1 << 16) {
                x >>= 16;
                msb += 16;
            }
            if (x >= 1 << 8) {
                x >>= 8;
                msb += 8;
            }
            if (x >= 1 << 4) {
                x >>= 4;
                msb += 4;
            }
            if (x >= 1 << 2) {
                x >>= 2;
                msb += 2;
            }
            if (x >= 1 << 1) {
                msb += 1;
            }
        }
    }

    /// @notice Returns the index of the least significant bit of x
    /// @param x The value as a uint256
    /// @return lsb The index of the least significant bit of x
    function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) {
        unchecked {
            if (x << 128 != 0) {
                x <<= 128;
                lsb = 128;
            }
            if (x << 64 != 0) {
                x <<= 64;
                lsb += 64;
            }
            if (x << 32 != 0) {
                x <<= 32;
                lsb += 32;
            }
            if (x << 16 != 0) {
                x <<= 16;
                lsb += 16;
            }
            if (x << 8 != 0) {
                x <<= 8;
                lsb += 8;
            }
            if (x << 4 != 0) {
                x <<= 4;
                lsb += 4;
            }
            if (x << 2 != 0) {
                x <<= 2;
                lsb += 2;
            }
            if (x << 1 != 0) {
                lsb += 1;
            }

            return 255 - lsb;
        }
    }
}

File 16 of 25 : Constants.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Constants Library
/// @author Trader Joe
/// @notice Set of constants for Liquidity Book contracts
library Constants {
    uint256 internal constant SCALE_OFFSET = 128;
    uint256 internal constant SCALE = 1 << SCALE_OFFSET;

    uint256 internal constant PRECISION = 1e18;
    uint256 internal constant BASIS_POINT_MAX = 10_000;

    /// @dev The expected return after a successful flash loan
    bytes32 internal constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
}

File 17 of 25 : FeeDistributionHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./Constants.sol";
import "./FeeHelper.sol";

/// @title Liquidity Book Fee Distribution Helper Library
/// @author Trader Joe
/// @notice Helper contract used for fees distribution calculations
library FeeDistributionHelper {
    /// @notice Calculate the tokenPerShare when fees are added
    /// @param _fees The fees received by the pair
    /// @param _totalSupply the total supply of a specific bin
    function getTokenPerShare(FeeHelper.FeesDistribution memory _fees, uint256 _totalSupply)
        internal
        pure
        returns (uint256)
    {
        unchecked {
            // This can't overflow as `totalFees >= protocolFees`,
            // shift can't overflow as we shift fees that are a uint128, by 128 bits.
            // The result will always be smaller than max(uint256)
            return ((uint256(_fees.total) - _fees.protocol) << Constants.SCALE_OFFSET) / _totalSupply;
        }
    }
}

File 18 of 25 : FeeHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./Constants.sol";
import "./SafeCast.sol";
import "./SafeMath.sol";

/// @title Liquidity Book Fee Helper Library
/// @author Trader Joe
/// @notice Helper contract used for fees calculation
library FeeHelper {
    using SafeCast for uint256;
    using SafeMath for uint256;

    /// @dev Structure to store the protocol fees:
    /// - binStep: The bin step
    /// - baseFactor: The base factor
    /// - filterPeriod: The filter period, where the fees stays constant
    /// - decayPeriod: The decay period, where the fees are halved
    /// - reductionFactor: The reduction factor, used to calculate the reduction of the accumulator
    /// - variableFeeControl: The variable fee control, used to control the variable fee, can be 0 to disable them
    /// - protocolShare: The share of fees sent to protocol
    /// - maxVolatilityAccumulated: The max value of volatility accumulated
    /// - volatilityAccumulated: The value of volatility accumulated
    /// - volatilityReference: The value of volatility reference
    /// - indexRef: The index reference
    /// - time: The last time the accumulator was called
    struct FeeParameters {
        // 144 lowest bits in slot
        uint16 binStep;
        uint16 baseFactor;
        uint16 filterPeriod;
        uint16 decayPeriod;
        uint16 reductionFactor;
        uint24 variableFeeControl;
        uint16 protocolShare;
        uint24 maxVolatilityAccumulated;
        // 112 highest bits in slot
        uint24 volatilityAccumulated;
        uint24 volatilityReference;
        uint24 indexRef;
        uint40 time;
    }

    /// @dev Structure used during swaps to distributes the fees:
    /// - total: The total amount of fees
    /// - protocol: The amount of fees reserved for protocol
    struct FeesDistribution {
        uint128 total;
        uint128 protocol;
    }

    /// @notice Update the value of the volatility accumulated
    /// @param _fp The current fee parameters
    /// @param _activeId The current active id
    function updateVariableFeeParameters(FeeParameters memory _fp, uint256 _activeId) internal view {
        uint256 _deltaT = block.timestamp - _fp.time;

        if (_deltaT >= _fp.filterPeriod || _fp.time == 0) {
            _fp.indexRef = uint24(_activeId);
            if (_deltaT < _fp.decayPeriod) {
                unchecked {
                    // This can't overflow as `reductionFactor <= BASIS_POINT_MAX`
                    _fp.volatilityReference = uint24(
                        (uint256(_fp.reductionFactor) * _fp.volatilityAccumulated) / Constants.BASIS_POINT_MAX
                    );
                }
            } else {
                _fp.volatilityReference = 0;
            }
        }

        _fp.time = (block.timestamp).safe40();

        updateVolatilityAccumulated(_fp, _activeId);
    }

    /// @notice Update the volatility accumulated
    /// @param _fp The fee parameter
    /// @param _activeId The current active id
    function updateVolatilityAccumulated(FeeParameters memory _fp, uint256 _activeId) internal pure {
        uint256 volatilityAccumulated = (_activeId.absSub(_fp.indexRef) * Constants.BASIS_POINT_MAX) +
            _fp.volatilityReference;
        _fp.volatilityAccumulated = volatilityAccumulated > _fp.maxVolatilityAccumulated
            ? _fp.maxVolatilityAccumulated
            : uint24(volatilityAccumulated);
    }

    /// @notice Returns the base fee added to a swap, with 18 decimals
    /// @param _fp The current fee parameters
    /// @return The fee with 18 decimals precision
    function getBaseFee(FeeParameters memory _fp) internal pure returns (uint256) {
        unchecked {
            return uint256(_fp.baseFactor) * _fp.binStep * 1e10;
        }
    }

    /// @notice Returns the variable fee added to a swap, with 18 decimals
    /// @param _fp The current fee parameters
    /// @return variableFee The variable fee with 18 decimals precision
    function getVariableFee(FeeParameters memory _fp) internal pure returns (uint256 variableFee) {
        if (_fp.variableFeeControl != 0) {
            // Can't overflow as the max value is `max(uint24) * (max(uint24) * max(uint16)) ** 2 < max(uint104)`
            // It returns 18 decimals as:
            // decimals(variableFeeControl * (volatilityAccumulated * binStep)**2 / 100) = 4 + (4 + 4) * 2 - 2 = 18
            unchecked {
                uint256 _prod = uint256(_fp.volatilityAccumulated) * _fp.binStep;
                variableFee = (_prod * _prod * _fp.variableFeeControl + 99) / 100;
            }
        }
    }

    /// @notice Return the amount of fees from an amount
    /// @dev Rounds amount up, follows `amount = amountWithFees - getFeeAmountFrom(fp, amountWithFees)`
    /// @param _fp The current fee parameter
    /// @param _amountWithFees The amount of token sent
    /// @return The fee amount from the amount sent
    function getFeeAmountFrom(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) {
        return (_amountWithFees * getTotalFee(_fp) + Constants.PRECISION - 1) / (Constants.PRECISION);
    }

    /// @notice Return the fees to add to an amount
    /// @dev Rounds amount up, follows `amountWithFees = amount + getFeeAmount(fp, amount)`
    /// @param _fp The current fee parameter
    /// @param _amount The amount of token sent
    /// @return The fee amount to add to the amount
    function getFeeAmount(FeeParameters memory _fp, uint256 _amount) internal pure returns (uint256) {
        uint256 _fee = getTotalFee(_fp);
        uint256 _denominator = Constants.PRECISION - _fee;
        return (_amount * _fee + _denominator - 1) / _denominator;
    }

    /// @notice Return the fees added when an user adds liquidity and change the ratio in the active bin
    /// @dev Rounds amount up
    /// @param _fp The current fee parameter
    /// @param _amountWithFees The amount of token sent
    /// @return The fee amount
    function getFeeAmountForC(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) {
        uint256 _fee = getTotalFee(_fp);
        uint256 _denominator = Constants.PRECISION * Constants.PRECISION;
        return (_amountWithFees * _fee * (_fee + Constants.PRECISION) + _denominator - 1) / _denominator;
    }

    /// @notice Return the fees distribution added to an amount
    /// @param _fp The current fee parameter
    /// @param _fees The fee amount
    /// @return fees The fee distribution
    function getFeeAmountDistribution(FeeParameters memory _fp, uint256 _fees)
        internal
        pure
        returns (FeesDistribution memory fees)
    {
        fees.total = _fees.safe128();
        // unsafe math is fine because total >= protocol
        unchecked {
            fees.protocol = uint128((_fees * _fp.protocolShare) / Constants.BASIS_POINT_MAX);
        }
    }

    /// @notice Return the total fee, i.e. baseFee + variableFee
    /// @param _fp The current fee parameter
    /// @return The total fee, with 18 decimals
    function getTotalFee(FeeParameters memory _fp) private pure returns (uint256) {
        unchecked {
            return getBaseFee(_fp) + getVariableFee(_fp);
        }
    }
}

File 19 of 25 : JoeLibrary.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;

import "../LBErrors.sol";

/// @title Liquidity Book Joe Library Helper Library
/// @author Trader Joe
/// @notice Helper contract used for Joe V1 related calculations
library JoeLibrary {
    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        if (tokenA == tokenB) revert JoeLibrary__IdenticalAddresses();
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        if (token0 == address(0)) revert JoeLibrary__AddressZero();
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        if (amountA == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveA == 0 || reserveB == 0) revert JoeLibrary__InsufficientLiquidity();
        amountB = (amountA * reserveB) / reserveA;
    }

    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountOut) {
        if (amountIn == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity();
        uint256 amountInWithFee = amountIn * 997;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = reserveIn * 1000 + amountInWithFee;
        amountOut = numerator / denominator;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256 amountIn) {
        if (amountOut == 0) revert JoeLibrary__InsufficientAmount();
        if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity();
        uint256 numerator = reserveIn * amountOut * 1000;
        uint256 denominator = (reserveOut - amountOut) * 997;
        amountIn = numerator / denominator + 1;
    }
}

File 20 of 25 : Math128x128.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./BitMath.sol";
import "./Constants.sol";
import "./Math512Bits.sol";

/// @title Liquidity Book Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for power and log calculations
library Math128x128 {
    using Math512Bits for uint256;
    using BitMath for uint256;

    uint256 constant LOG_SCALE_OFFSET = 127;
    uint256 constant LOG_SCALE = 1 << LOG_SCALE_OFFSET;
    uint256 constant LOG_SCALE_SQUARED = LOG_SCALE * LOG_SCALE;

    /// @notice Calculates the binary logarithm of x.
    ///
    /// @dev Based on the iterative approximation algorithm.
    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
    ///
    /// Requirements:
    /// - x must be greater than zero.
    ///
    /// Caveats:
    /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation
    /// Also because x is converted to an unsigned 129.127-binary fixed-point number during the operation to optimize the multiplication
    ///
    /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the binary logarithm.
    /// @return result The binary logarithm as a signed 128.128-binary fixed-point number.
    function log2(uint256 x) internal pure returns (int256 result) {
        // Convert x to a unsigned 129.127-binary fixed-point number to optimize the multiplication.
        // If we use an offset of 128 bits, y would need 129 bits and y**2 would would overflow and we would have to
        // use mulDiv, by reducing x to 129.127-binary fixed-point number we assert that y will use 128 bits, and we
        // can use the regular multiplication

        if (x == 1) return -128;
        if (x == 0) revert Math128x128__LogUnderflow();

        x >>= 1;

        unchecked {
            // This works because log2(x) = -log2(1/x).
            int256 sign;
            if (x >= LOG_SCALE) {
                sign = 1;
            } else {
                sign = -1;
                // Do the fixed-point inversion inline to save gas
                x = LOG_SCALE_SQUARED / x;
            }

            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
            uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit();

            // The integer part of the logarithm as a signed 129.127-binary fixed-point number. The operation can't overflow
            // because n is maximum 255, LOG_SCALE_OFFSET is 127 bits and sign is either 1 or -1.
            result = int256(n) << LOG_SCALE_OFFSET;

            // This is y = x * 2^(-n).
            uint256 y = x >> n;

            // If y = 1, the fractional part is zero.
            if (y != LOG_SCALE) {
                // Calculate the fractional part via the iterative approximation.
                // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
                for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) {
                    y = (y * y) >> LOG_SCALE_OFFSET;

                    // Is y^2 > 2 and so in the range [2,4)?
                    if (y >= 1 << (LOG_SCALE_OFFSET + 1)) {
                        // Add the 2^(-m) factor to the logarithm.
                        result += delta;

                        // Corresponds to z/2 on Wikipedia.
                        y >>= 1;
                    }
                }
            }
            // Convert x back to unsigned 128.128-binary fixed-point number
            result = (result * sign) << 1;
        }
    }

    /// @notice Returns the value of x^y. It calculates `1 / x^abs(y)` if x is bigger than 2^128.
    /// At the end of the operations, we invert the result if needed.
    /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the power
    /// @param y A relative number without any decimals, needs to be between ]2^20; 2^20[
    /// @return result The result of `x^y`
    function power(uint256 x, int256 y) internal pure returns (uint256 result) {
        bool invert;
        uint256 absY;

        if (y == 0) return Constants.SCALE;

        assembly {
            absY := y
            if slt(absY, 0) {
                absY := sub(0, absY)
                invert := iszero(invert)
            }
        }

        if (absY < 0x100000) {
            result = Constants.SCALE;
            assembly {
                let pow := x
                if gt(x, 0xffffffffffffffffffffffffffffffff) {
                    pow := div(not(0), pow)
                    invert := iszero(invert)
                }

                if and(absY, 0x1) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x2) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x4) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x8) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x10) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x20) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x40) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x80) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x100) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x200) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x400) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x800) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x1000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x2000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x4000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x8000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x10000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x20000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x40000) {
                    result := shr(128, mul(result, pow))
                }
                pow := shr(128, mul(pow, pow))
                if and(absY, 0x80000) {
                    result := shr(128, mul(result, pow))
                }
            }
        }

        // revert if y is too big or if x^y underflowed
        if (result == 0) revert Math128x128__PowerUnderflow(x, y);

        return invert ? type(uint256).max / result : result;
    }
}

File 21 of 25 : Math512Bits.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";
import "./BitMath.sol";

/// @title Liquidity Book Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for full precision calculations
library Math512Bits {
    using BitMath for uint256;

    /// @notice Calculates floor(x*y÷denominator) with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The denominator cannot be zero
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function mulDivRoundDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        (uint256 prod0, uint256 prod1) = _getMulProds(x, y);

        return _getEndOfDivRoundDown(x, y, denominator, prod0, prod1);
    }

    /// @notice Calculates x * y >> offset with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param offset The offset as an uint256, can't be greater than 256
    /// @return result The result as an uint256
    function mulShiftRoundDown(
        uint256 x,
        uint256 y,
        uint256 offset
    ) internal pure returns (uint256 result) {
        if (offset > 255) revert Math512Bits__OffsetOverflows(offset);

        (uint256 prod0, uint256 prod1) = _getMulProds(x, y);

        if (prod0 != 0) result = prod0 >> offset;
        if (prod1 != 0) {
            // Make sure the result is less than 2^256.
            if (prod1 >= 1 << offset) revert Math512Bits__MulShiftOverflow(prod1, offset);

            unchecked {
                result += prod1 << (256 - offset);
            }
        }
    }

    /// @notice Calculates x * y >> offset with full precision
    /// The result will be rounded up
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param offset The offset as an uint256, can't be greater than 256
    /// @return result The result as an uint256
    function mulShiftRoundUp(
        uint256 x,
        uint256 y,
        uint256 offset
    ) internal pure returns (uint256 result) {
        unchecked {
            result = mulShiftRoundDown(x, y, offset);
            if (mulmod(x, y, 1 << offset) != 0) result += 1;
        }
    }

    /// @notice Calculates x << offset / y with full precision
    /// The result will be rounded down
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param offset The number of bit to shift x as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function shiftDivRoundDown(
        uint256 x,
        uint256 offset,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        if (offset > 255) revert Math512Bits__OffsetOverflows(offset);
        uint256 prod0;
        uint256 prod1;

        prod0 = x << offset; // Least significant 256 bits of the product
        unchecked {
            prod1 = x >> (256 - offset); // Most significant 256 bits of the product
        }

        return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1);
    }

    /// @notice Calculates x << offset / y with full precision
    /// The result will be rounded up
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    ///
    /// Requirements:
    /// - The offset needs to be strictly lower than 256
    /// - The result must fit within uint256
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers
    ///
    /// @param x The multiplicand as an uint256
    /// @param offset The number of bit to shift x as an uint256
    /// @param denominator The divisor as an uint256
    /// @return result The result as an uint256
    function shiftDivRoundUp(
        uint256 x,
        uint256 offset,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = shiftDivRoundDown(x, offset, denominator);
        unchecked {
            if (mulmod(x, 1 << offset, denominator) != 0) result += 1;
        }
    }

    /// @notice Helper function to return the result of `x * y` as 2 uint256
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @return prod0 The least significant 256 bits of the product
    /// @return prod1 The most significant 256 bits of the product
    function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) {
        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
        // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = prod1 * 2^256 + prod0.
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }
    }

    /// @notice Helper function to return the result of `x * y / denominator` with full precision
    /// @param x The multiplicand as an uint256
    /// @param y The multiplier as an uint256
    /// @param denominator The divisor as an uint256
    /// @param prod0 The least significant 256 bits of the product
    /// @param prod1 The most significant 256 bits of the product
    /// @return result The result as an uint256
    function _getEndOfDivRoundDown(
        uint256 x,
        uint256 y,
        uint256 denominator,
        uint256 prod0,
        uint256 prod1
    ) private pure returns (uint256 result) {
        // Handle non-overflow cases, 256 by 256 division
        if (prod1 == 0) {
            unchecked {
                result = prod0 / denominator;
            }
        } else {
            // Make sure the result is less than 2^256. Also prevents denominator == 0
            if (prod1 >= denominator) revert Math512Bits__MulDivOverflow(prod1, denominator);

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1
            // See https://cs.stackexchange.com/q/138556/92363
            unchecked {
                // Does not overflow because the denominator cannot be zero at this stage in the function
                uint256 lpotdod = denominator & (~denominator + 1);
                assembly {
                    // Divide denominator by lpotdod.
                    denominator := div(denominator, lpotdod)

                    // Divide [prod1 prod0] by lpotdod.
                    prod0 := div(prod0, lpotdod)

                    // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one
                    lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
                }

                // Shift in bits from prod1 into prod0
                prod0 |= prod1 * lpotdod;

                // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                // four bits. That is, denominator * inv = 1 mod 2^4
                uint256 inverse = (3 * denominator) ^ 2;

                // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                // in modular arithmetic, doubling the correct bits in each step
                inverse *= 2 - denominator * inverse; // inverse mod 2^8
                inverse *= 2 - denominator * inverse; // inverse mod 2^16
                inverse *= 2 - denominator * inverse; // inverse mod 2^32
                inverse *= 2 - denominator * inverse; // inverse mod 2^64
                inverse *= 2 - denominator * inverse; // inverse mod 2^128
                inverse *= 2 - denominator * inverse; // inverse mod 2^256

                // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                // is no longer required.
                result = prod0 * inverse;
            }
        }
    }
}

File 22 of 25 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../LBErrors.sol";

/// @title Liquidity Book Safe Cast Library
/// @author Trader Joe
/// @notice Helper contract used for converting uint values safely
library SafeCast {
    /// @notice Returns x on uint248 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint248
    function safe248(uint256 x) internal pure returns (uint248 y) {
        if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits(x);
    }

    /// @notice Returns x on uint240 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint240
    function safe240(uint256 x) internal pure returns (uint240 y) {
        if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits(x);
    }

    /// @notice Returns x on uint232 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint232
    function safe232(uint256 x) internal pure returns (uint232 y) {
        if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits(x);
    }

    /// @notice Returns x on uint224 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint224
    function safe224(uint256 x) internal pure returns (uint224 y) {
        if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits(x);
    }

    /// @notice Returns x on uint216 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint216
    function safe216(uint256 x) internal pure returns (uint216 y) {
        if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits(x);
    }

    /// @notice Returns x on uint208 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint208
    function safe208(uint256 x) internal pure returns (uint208 y) {
        if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits(x);
    }

    /// @notice Returns x on uint200 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint200
    function safe200(uint256 x) internal pure returns (uint200 y) {
        if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits(x);
    }

    /// @notice Returns x on uint192 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint192
    function safe192(uint256 x) internal pure returns (uint192 y) {
        if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits(x);
    }

    /// @notice Returns x on uint184 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint184
    function safe184(uint256 x) internal pure returns (uint184 y) {
        if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits(x);
    }

    /// @notice Returns x on uint176 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint176
    function safe176(uint256 x) internal pure returns (uint176 y) {
        if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits(x);
    }

    /// @notice Returns x on uint168 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint168
    function safe168(uint256 x) internal pure returns (uint168 y) {
        if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits(x);
    }

    /// @notice Returns x on uint160 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint160
    function safe160(uint256 x) internal pure returns (uint160 y) {
        if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits(x);
    }

    /// @notice Returns x on uint152 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint152
    function safe152(uint256 x) internal pure returns (uint152 y) {
        if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits(x);
    }

    /// @notice Returns x on uint144 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint144
    function safe144(uint256 x) internal pure returns (uint144 y) {
        if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits(x);
    }

    /// @notice Returns x on uint136 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint136
    function safe136(uint256 x) internal pure returns (uint136 y) {
        if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits(x);
    }

    /// @notice Returns x on uint128 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint128
    function safe128(uint256 x) internal pure returns (uint128 y) {
        if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits(x);
    }

    /// @notice Returns x on uint120 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint120
    function safe120(uint256 x) internal pure returns (uint120 y) {
        if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits(x);
    }

    /// @notice Returns x on uint112 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint112
    function safe112(uint256 x) internal pure returns (uint112 y) {
        if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits(x);
    }

    /// @notice Returns x on uint104 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint104
    function safe104(uint256 x) internal pure returns (uint104 y) {
        if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits(x);
    }

    /// @notice Returns x on uint96 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint96
    function safe96(uint256 x) internal pure returns (uint96 y) {
        if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits(x);
    }

    /// @notice Returns x on uint88 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint88
    function safe88(uint256 x) internal pure returns (uint88 y) {
        if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits(x);
    }

    /// @notice Returns x on uint80 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint80
    function safe80(uint256 x) internal pure returns (uint80 y) {
        if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits(x);
    }

    /// @notice Returns x on uint72 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint72
    function safe72(uint256 x) internal pure returns (uint72 y) {
        if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits(x);
    }

    /// @notice Returns x on uint64 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint64
    function safe64(uint256 x) internal pure returns (uint64 y) {
        if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits(x);
    }

    /// @notice Returns x on uint56 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint56
    function safe56(uint256 x) internal pure returns (uint56 y) {
        if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits(x);
    }

    /// @notice Returns x on uint48 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint48
    function safe48(uint256 x) internal pure returns (uint48 y) {
        if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits(x);
    }

    /// @notice Returns x on uint40 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint40
    function safe40(uint256 x) internal pure returns (uint40 y) {
        if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits(x);
    }

    /// @notice Returns x on uint32 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint32
    function safe32(uint256 x) internal pure returns (uint32 y) {
        if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits(x);
    }

    /// @notice Returns x on uint24 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint24
    function safe24(uint256 x) internal pure returns (uint24 y) {
        if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits(x);
    }

    /// @notice Returns x on uint16 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint16
    function safe16(uint256 x) internal pure returns (uint16 y) {
        if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits(x);
    }

    /// @notice Returns x on uint8 and check that it does not overflow
    /// @param x The value as an uint256
    /// @return y The value as an uint8
    function safe8(uint256 x) internal pure returns (uint8 y) {
        if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits(x);
    }
}

File 23 of 25 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/// @title Liquidity Book Safe Math Helper Library
/// @author Trader Joe
/// @notice Helper contract used for calculating absolute value safely
library SafeMath {
    /// @notice absSub, can't underflow or overflow
    /// @param x The first value
    /// @param y The second value
    /// @return The result of abs(x - y)
    function absSub(uint256 x, uint256 y) internal pure returns (uint256) {
        unchecked {
            return x > y ? x - y : y - x;
        }
    }
}

File 24 of 25 : SwapHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./BinHelper.sol";
import "./Constants.sol";
import "./FeeDistributionHelper.sol";
import "./FeeHelper.sol";
import "./Math512Bits.sol";
import "./SafeMath.sol";
import "../interfaces/ILBPair.sol";

/// @title Liquidity Book Swap Helper Library
/// @author Trader Joe
/// @notice Helper contract used for calculating swaps, fees and reserves changes
library SwapHelper {
    using Math512Bits for uint256;
    using FeeHelper for FeeHelper.FeeParameters;
    using SafeMath for uint256;
    using FeeDistributionHelper for FeeHelper.FeesDistribution;

    /// @notice Returns the swap amounts in the current bin
    /// @param bin The bin information
    /// @param fp The fee parameters
    /// @param activeId The active id of the pair
    /// @param swapForY Whether you've swapping token X for token Y (true) or token Y for token X (false)
    /// @param amountIn The amount sent by the user
    /// @return amountInToBin The amount of token that is added to the bin without the fees
    /// @return amountOutOfBin The amount of token that is removed from the bin
    /// @return fees The swap fees
    function getAmounts(
        ILBPair.Bin memory bin,
        FeeHelper.FeeParameters memory fp,
        uint256 activeId,
        bool swapForY,
        uint256 amountIn
    )
        internal
        pure
        returns (
            uint256 amountInToBin,
            uint256 amountOutOfBin,
            FeeHelper.FeesDistribution memory fees
        )
    {
        uint256 _price = BinHelper.getPriceFromId(activeId, fp.binStep);

        uint256 _reserve;
        uint256 _maxAmountInToBin;
        if (swapForY) {
            _reserve = bin.reserveY;
            _maxAmountInToBin = _reserve.shiftDivRoundUp(Constants.SCALE_OFFSET, _price);
        } else {
            _reserve = bin.reserveX;
            _maxAmountInToBin = _price.mulShiftRoundUp(_reserve, Constants.SCALE_OFFSET);
        }

        fp.updateVolatilityAccumulated(activeId);
        fees = fp.getFeeAmountDistribution(fp.getFeeAmount(_maxAmountInToBin));

        if (_maxAmountInToBin + fees.total <= amountIn) {
            amountInToBin = _maxAmountInToBin;
            amountOutOfBin = _reserve;
        } else {
            fees = fp.getFeeAmountDistribution(fp.getFeeAmountFrom(amountIn));
            amountInToBin = amountIn - fees.total;
            amountOutOfBin = swapForY
                ? _price.mulShiftRoundDown(amountInToBin, Constants.SCALE_OFFSET)
                : amountInToBin.shiftDivRoundDown(Constants.SCALE_OFFSET, _price);
            // Safety check in case rounding returns a higher value than expected
            if (amountOutOfBin > _reserve) amountOutOfBin = _reserve;
        }
    }

    /// @notice Update the fees of the pair and accumulated token per share of the bin
    /// @param bin The bin information
    /// @param pairFees The current fees of the pair information
    /// @param fees The fees amounts added to the pairFees
    /// @param swapForY whether the token sent was Y (true) or X (false)
    /// @param totalSupply The total supply of the token id
    function updateFees(
        ILBPair.Bin memory bin,
        FeeHelper.FeesDistribution memory pairFees,
        FeeHelper.FeesDistribution memory fees,
        bool swapForY,
        uint256 totalSupply
    ) internal pure {
        pairFees.total += fees.total;
        // unsafe math is fine because total >= protocol
        unchecked {
            pairFees.protocol += fees.protocol;
        }

        if (swapForY) {
            bin.accTokenXPerShare += fees.getTokenPerShare(totalSupply);
        } else {
            bin.accTokenYPerShare += fees.getTokenPerShare(totalSupply);
        }
    }

    /// @notice Update reserves
    /// @param bin The bin information
    /// @param pair The pair information
    /// @param swapForY whether the token sent was Y (true) or X (false)
    /// @param amountInToBin The amount of token that is added to the bin without fees
    /// @param amountOutOfBin The amount of token that is removed from the bin
    function updateReserves(
        ILBPair.Bin memory bin,
        ILBPair.PairInformation memory pair,
        bool swapForY,
        uint112 amountInToBin,
        uint112 amountOutOfBin
    ) internal pure {
        if (swapForY) {
            bin.reserveX += amountInToBin;

            unchecked {
                bin.reserveY -= amountOutOfBin;
                pair.reserveX += uint136(amountInToBin);
                pair.reserveY -= uint136(amountOutOfBin);
            }
        } else {
            bin.reserveY += amountInToBin;

            unchecked {
                bin.reserveX -= amountOutOfBin;
                pair.reserveX -= uint136(amountOutOfBin);
                pair.reserveY += uint136(amountInToBin);
            }
        }
    }
}

File 25 of 25 : TokenHelper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "openzeppelin/token/ERC20/IERC20.sol";

import "../LBErrors.sol";

/// @title Safe Transfer
/// @author Trader Joe
/// @notice Wrappers around ERC20 operations that throw on failure (when the token
/// contract returns false). Tokens that return no value (and instead revert or
/// throw on failure) are also supported, non-reverting calls are assumed to be
/// successful.
/// To use this library you can add a `using TokenHelper for IERC20;` statement to your contract,
/// which allows you to call the safe operation as `token.safeTransfer(...)`
library TokenHelper {
    /// @notice Transfers token only if the amount is greater than zero
    /// @param token The address of the token
    /// @param owner The owner of the tokens
    /// @param recipient The address of the recipient
    /// @param amount The amount to send
    function safeTransferFrom(
        IERC20 token,
        address owner,
        address recipient,
        uint256 amount
    ) internal {
        if (amount != 0) {
            bytes memory data = abi.encodeWithSelector(token.transferFrom.selector, owner, recipient, amount);

            bytes memory returnData = _callAndCatchError(address(token), data);

            if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
        }
    }

    /// @notice Transfers token only if the amount is greater than zero
    /// @param token The address of the token
    /// @param recipient The address of the recipient
    /// @param amount The amount to send
    function safeTransfer(
        IERC20 token,
        address recipient,
        uint256 amount
    ) internal {
        if (amount != 0) {
            bytes memory data = abi.encodeWithSelector(token.transfer.selector, recipient, amount);

            bytes memory returnData = _callAndCatchError(address(token), data);

            if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
        }
    }

    /// @notice Returns the amount of token received by the pair
    /// @param token The address of the token
    /// @param reserve The total reserve of token
    /// @param fees The total fees of token
    /// @return The amount received by the pair
    function received(
        IERC20 token,
        uint256 reserve,
        uint256 fees
    ) internal view returns (uint256) {
        uint256 _internalBalance;
        unchecked {
            _internalBalance = reserve + fees;
        }
        return token.balanceOf(address(this)) - _internalBalance;
    }

    /// @notice Private view function to perform a low level call on `target`
    /// @dev Revert if the call doesn't succeed
    /// @param target The address of the account
    /// @param data The data to execute on `target`
    /// @return returnData The data returned by the call
    function _callAndCatchError(address target, bytes memory data) private returns (bytes memory) {
        (bool success, bytes memory returnData) = target.call(data);

        if (success) {
            if (returnData.length == 0 && !_isContract(target)) revert TokenHelper__NonContract();
        } else {
            if (returnData.length == 0) revert TokenHelper__CallFailed();
            else {
                // Look for revert reason and bubble it up if present
                assembly {
                    revert(add(32, returnData), mload(returnData))
                }
            }
        }

        return returnData;
    }

    /// @notice Private view function to return if an address is a contract
    /// @dev It is unsafe to assume that an address for which this function returns
    /// false is an externally-owned account (EOA) and not a contract.
    ///
    /// Among others, `isContract` will return false for the following
    /// types of addresses:
    ///  - an externally-owned account
    ///  - a contract in construction
    ///  - an address where a contract will be created
    ///  - an address where a contract lived, but was destroyed
    /// @param account The address of the account
    /// @return Whether the account is a contract (true) or not (false)
    function _isContract(address account) private view returns (bool) {
        return account.code.length > 0;
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"contract ILBFactory","name":"_factory","type":"address"},{"internalType":"contract IJoeFactory","name":"_oldFactory","type":"address"},{"internalType":"contract IWAVAX","name":"_wavax","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"BinHelper__BinStepOverflows","type":"error"},{"inputs":[],"name":"BinHelper__IdOverflows","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientAmount","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientLiquidity","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"LBRouter__AmountSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__BinReserveOverflows","type":"error"},{"inputs":[],"name":"LBRouter__BrokenSwapSafetyCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"}],"name":"LBRouter__DeadlineExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LBRouter__FailedToSendAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"idDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"}],"name":"LBRouter__IdDesiredOverflows","type":"error"},{"inputs":[{"internalType":"int256","name":"id","type":"int256"}],"name":"LBRouter__IdOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"uint256","name":"activeId","type":"uint256"}],"name":"LBRouter__IdSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"LBRouter__InsufficientAmountOut","type":"error"},{"inputs":[{"internalType":"address","name":"wrongToken","type":"address"}],"name":"LBRouter__InvalidTokenPath","type":"error"},{"inputs":[],"name":"LBRouter__LengthsMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"LBRouter__MaxAmountInExceeded","type":"error"},{"inputs":[],"name":"LBRouter__NotFactoryOwner","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBRouter__PairNotCreated","type":"error"},{"inputs":[],"name":"LBRouter__SenderIsNotWAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__SwapOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"excess","type":"uint256"}],"name":"LBRouter__TooMuchTokensIn","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"LBRouter__WrongAmounts","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"LBRouter__WrongAvaxLiquidityParameters","type":"error"},{"inputs":[],"name":"LBRouter__WrongTokenOrder","type":"error"},{"inputs":[],"name":"Math128x128__LogUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Math128x128__PowerUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"Math512Bits__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__MulShiftOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__OffsetOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds128Bits","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds40Bits","type":"error"},{"inputs":[],"name":"TokenHelper__CallFailed","type":"error"},{"inputs":[],"name":"TokenHelper__NonContract","type":"error"},{"inputs":[],"name":"TokenHelper__TransferFailed","type":"error"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","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":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidity","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","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":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidityAVAX","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint24","name":"_activeId","type":"uint24"},{"internalType":"uint16","name":"_binStep","type":"uint16"}],"name":"createLBPair","outputs":[{"internalType":"contract ILBPair","name":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract ILBFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getIdFromPrice","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint24","name":"_id","type":"uint24"}],"name":"getPriceFromId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oldFactory","outputs":[{"internalType":"contract IJoeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountXMin","type":"uint256"},{"internalType":"uint256","name":"_amountYMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"_amountAVAXMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidityAVAX","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountAVAX","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapAVAXForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAX","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAXSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountAVAXOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactAVAX","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILBToken","name":"_lbToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"sweepLBToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wavax","outputs":[{"internalType":"contract IWAVAX","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b5060405162005ae038038062005ae083398101604081905262000034916200006b565b6001600160a01b0392831660805290821660a0521660c052620000bf565b6001600160a01b03811681146200006857600080fd5b50565b6000806000606084860312156200008157600080fd5b83516200008e8162000052565b6020850151909350620000a18162000052565b6040850151909250620000b48162000052565b809150509250925092565b60805160a05160c0516159496200019760003960008181610194015281816101eb01528181610ac301528181610c3d01528181610e640152818161170a0152818161185f01528181611948015281816119db01528181611a9e01528181611b5e01528181611d1101528181611dab01528181611e3501528181612332015281816123b0015281816125610152818161263a01528181612eac0152612f2a01526000818161023c01526143200152600081816104390152818161139001528181611533015281816121510152613b7301526159496000f3fe6080604052600436106101845760003560e01c80636d3420ed116100d6578063d0e380f21161007f578063ea8f43d811610059578063ea8f43d8146104c9578063f96fe925146104dc578063fb321c701461051057600080fd5b8063d0e380f21461045b578063e324a3e41461047b578063e9361c08146104a957600080fd5b8063bcb1c957116100b0578063bcb1c957146103e7578063c22159b614610407578063c45a01551461042757600080fd5b80636d3420ed146103875780639a17e820146103a7578063a7b856d3146103c757600080fd5b806342f564a01161013857806362c067671161011257806362c0676714610327578063659ac74b146103475780636d0ff4951461036757600080fd5b806342f564a0146102d4578063440830bd146102f45780635bdd4b7c1461030757600080fd5b80632004b724116101695780632004b7241461025e578063212a1d9414610293578063264bb94e146102c157600080fd5b8063117be4c2146101d95780631bd6dfe11461022a57600080fd5b366101d457336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101d2576040516310d0bef760e31b815260040160405180910390fd5b005b600080fd5b3480156101e557600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023657600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561026a57600080fd5b5061027e610279366004614bc9565b610530565b60408051928352602083019190915201610221565b34801561029f57600080fd5b506102b36102ae366004614d7a565b610839565b604051908152602001610221565b6102b36102cf366004614e0e565b610a57565b6102e76102e2366004614e0e565b610bd1565b6040516102219190614ed1565b6102b3610302366004614e0e565b610df8565b34801561031357600080fd5b5061027e610322366004614bc9565b61103d565b34801561033357600080fd5b506101d2610342366004614ee4565b61138e565b34801561035357600080fd5b5061020d610362366004614f51565b6114f4565b34801561037357600080fd5b506102b3610382366004614d7a565b6115ab565b34801561039357600080fd5b506102e76103a2366004614d7a565b61169e565b3480156103b357600080fd5b506102b36103c2366004614d7a565b6118dc565b3480156103d357600080fd5b506102e76103e2366004614d7a565b611bcc565b3480156103f357600080fd5b5061027e610402366004614fad565b611cdb565b34801561041357600080fd5b5061027e610422366004615068565b611eb3565b34801561043357600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561046757600080fd5b506102b3610476366004615130565b611fa7565b34801561048757600080fd5b5061049b610496366004615169565b612028565b6040516102219291906151a5565b3480156104b557600080fd5b506101d26104c4366004615216565b61214f565b61049b6104d7366004615169565b612272565b3480156104e857600080fd5b506104fc6104f73660046152ab565b612482565b60405162ffffff9091168152602001610221565b34801561051c57600080fd5b506102b361052b366004614d7a565b6124f5565b6000806000856001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059791906152d7565b925050506000866001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156105dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106009190615330565b905061060c81836126a8565b6040805160808101825260008082526020820181905291810182905260608101919091525b604051630157d2d160e31b815262ffffff8416600482015260009081906001600160a01b038b1690630abe9688906024016040805180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a2919061541c565b604080516080810182526001600160701b03938416808252939092166020830152600090820181905260608201529350151591508190506106ef575060208101516001600160701b031615155b1561078557600080806107058486888c8e612765565b919450925090506001600160701b0383111561073c57604051633d9af4e160e11b8152600481018790526024015b60405180910390fd5b8051610751906001600160801b031684615456565b61075b908b61546e565b8151909a50610773906001600160801b031688615456565b965061077f8289615456565b97505050505b861561080c57604051638f919a8360e01b815262ffffff8416600482015286151560248201526001600160a01b03891690638f919a8390604401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190615485565b62ffffff169250610631565b861561082e576040516349cda5cd60e11b815260048101889052602401610733565b505050935093915050565b600081804211156108665760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610885575080518251610882906001615456565b14155b156108a35760405163b91b4d4d60e01b815260040160405180910390fd5b60006108af8989612889565b90506000888251815181106108c6576108c66154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561091d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094191906154b8565b9050610997338460008151811061095a5761095a6154a2565b60200260200101518f8d600081518110610976576109766154a2565b60200260200101516001600160a01b031661297e909392919063ffffffff16565b6109a3838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa1580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1091906154b8565b610a1a919061546e565b9650868c1115610a47576040516313fab00360e21b8152600481018d905260248101889052604401610733565b5050505050509695505050505050565b60008180421115610a845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610aa3575080518251610aa0906001615456565b14155b15610ac15760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610afe57610afe6154a2565b60200260200101516001600160a01b031614610b585786600081518110610b2757610b276154a2565b602002602001015160405163cfec0e0160e01b815260040161073391906001600160a01b0391909116815260200190565b6000610b648989612889565b9050610b8a81600081518110610b7c57610b7c6154a2565b602002602001015134612eaa565b610b9734828b8b8b612f59565b9450848a1115610bc4576040516313fab00360e21b8152600481018b905260248101869052604401610733565b5050505095945050505050565b60608180421115610bfe5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610c1d575080518251610c1a906001615456565b14155b15610c3b5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610c7857610c786154a2565b60200260200101516001600160a01b031614610ca15786600081518110610b2757610b276154a2565b6000610cad8989612889565b9050610cbb89828a8d6132da565b94503485600081518110610cd157610cd16154a2565b60200260200101511115610d1f573485600081518110610cf357610cf36154a2565b602002602001015160405163194ee21960e31b8152600401610733929190918252602082015260400190565b610d5d81600081518110610d3557610d356154a2565b602002602001015186600081518110610d5057610d506154a2565b6020026020010151612eaa565b6000610d6c828b8b898c6135c5565b90508a811015610d99576040516313fab00360e21b8152600481018c905260248101829052604401610733565b85600081518110610dac57610dac6154a2565b6020026020010151341115610dea57610dea3387600081518110610dd257610dd26154a2565b602002602001015134610de5919061546e565b613894565b505050505095945050505050565b60008180421115610e255760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610e44575080518251610e41906001615456565b14155b15610e625760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610e9f57610e9f6154a2565b60200260200101516001600160a01b031614610ec85786600081518110610b2757610b276154a2565b6000610ed48989612889565b9050600088825181518110610eeb57610eeb6154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6691906154b8565b9050610f7e83600081518110610b7c57610b7c6154a2565b610f8a838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff791906154b8565b611001919061546e565b9650868c111561102e576040516313fab00360e21b8152600481018d905260248101889052604401610733565b50505050505095945050505050565b6000806000806000876001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a791906152d7565b92509250925086600014806110c85750856110c4578287116110c8565b8187115b156110fd5786866110d957836110db565b825b604051637c40a4df60e01b815260048101929092526024820152604401610733565b6000886001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190615330565b905061116e81836126a8565b60008060005b604051630157d2d160e31b815262ffffff8616600482015260009081906001600160a01b038f1690630abe9688906024016040805180830381865afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061541c565b915091508b6111f457816111f6565b805b92505050600061120e86866000015161ffff1661391a565b905081156112cd57818c1015611224578b611226565b815b935060008b6112405761123b82866080613962565b61124c565b61124c85608084613995565b905061125886886139c7565b60006112648783613a39565b90506112708183615456565b94506001600160701b036112848587615456565b11156112a65760405163ec44eb8960e01b815260048101899052602401610733565b6112b0858d615456565b9b506112bc818c615456565b9a506112c8868f61546e565b9d5050505b8b1561135457604051638f919a8360e01b815262ffffff871660048201528b151560248201526001600160a01b038e1690638f919a8390604401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113489190615485565b62ffffff16955061135a565b50611360565b50611174565b8a1561137f576040516330b1335760e21b815260040160405180910390fd5b50505050505050935093915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141091906154d1565b6001600160a01b0316336001600160a01b03161461144157604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b03831661146b5760001981141561145c5750475b6114668282613894565b505050565b6000198114156114e0576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156114b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114dd91906154b8565b90505b6114666001600160a01b0384168383613a89565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063659ac74b906084016020604051808303816000875af115801561157e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a291906154d1565b95945050505050565b600081804211156115d85760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806115f75750805182516115f4906001615456565b14155b156116155760405163b91b4d4d60e01b815260040160405180910390fd5b60006116218989612889565b9050611656338260008151811061163a5761163a6154a2565b60200260200101518d8b600081518110610976576109766154a2565b6116638b828b8b8b612f59565b9450848a1115611690576040516313fab00360e21b8152600481018b905260248101869052604401610733565b505050509695505050505050565b606081804211156116cb5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806116ea5750805182516116e7906001615456565b14155b156117085760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611745576117456154a2565b60200260200101516001600160a01b03161461176e5786885181518110610b2757610b276154a2565b600061177a8989612889565b905061178889828a8e6132da565b9450898560008151811061179e5761179e6154a2565b602002602001015111156117c0578985600081518110610cf357610cf36154a2565b61180d33826000815181106117d7576117d76154a2565b6020026020010151876000815181106117f2576117f26154a2565b60200260200101518b600081518110610976576109766154a2565b600061181c828b8b89306135c5565b90508b811015611849576040516313fab00360e21b8152600481018d905260248101829052604401610733565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156118ab57600080fd5b505af11580156118bf573d6000803e3d6000fd5b505050506118cd8882613894565b50505050509695505050505050565b600081804211156119095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611928575080518251611925906001615456565b14155b156119465760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611983576119836154a2565b60200260200101516001600160a01b0316146119ac5786885181518110610b2757610b276154a2565b60006119b88989612889565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906154b8565b9050611a7b3383600081518110611a5f57611a5f6154a2565b60200260200101518e8c600081518110610976576109766154a2565b611a87828b8b30612a3f565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1191906154b8565b611b1b919061546e565b9550858b1115611b48576040516313fab00360e21b8152600481018c905260248101879052604401610733565b604051632e1a7d4d60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611baa57600080fd5b505af1158015611bbe573d6000803e3d6000fd5b505050506118cd8887613894565b60608180421115611bf95760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611c18575080518251611c15906001615456565b14155b15611c365760405163b91b4d4d60e01b815260040160405180910390fd5b6000611c428989612889565b9050611c5089828a8e6132da565b94508985600081518110611c6657611c666154a2565b60200260200101511115611c88578985600081518110610cf357610cf36154a2565b611c9f33826000815181106117d7576117d76154a2565b6000611cae828b8b898c6135c5565b90508b8110156118cd576040516313fab00360e21b8152600481018d905260248101829052604401610733565b6000808280421115611d095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611d3a8c7f00000000000000000000000000000000000000000000000000000000000000008d61ffff16613b40565b90506000816001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da091906154d1565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614905080611ddf579899985b600080611df0848e8e8e8e30613c25565b9150915082611e00578082611e03565b81815b9097509550611e1f9150506001600160a01b038e168887613a89565b604051632e1a7d4d60e01b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611e8157600080fd5b505af1158015611e95573d6000803e3d6000fd5b50505050611ea38785613894565b5050509850989650505050505050565b6000808280421115611ee15760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611ef28d8d8d61ffff16613b40565b90506000816001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5891906154d1565b6001600160a01b03168e6001600160a01b0316141590508015611f79579899985b611f87828c8c8c8c8c613c25565b90955093508015611f96579293925b505050995099975050505050505050565b600061201f8262ffffff16846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa158015611ff1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120159190615330565b5161ffff1661391a565b90505b92915050565b606080600061205761203d60208601866154ee565b61204d60408701602088016154ee565b8660400135613b40565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906154d1565b6001600160a01b03166120d160208601866154ee565b6001600160a01b0316146120f85760405163b33f8ab960e01b815260040160405180910390fd5b6121203382606087013561210f60208901896154ee565b6001600160a01b031692919061297e565b61213a3382608087013561210f6040890160208a016154ee565b6121448482613d51565b909590945092505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d191906154d1565b6001600160a01b0316336001600160a01b03161461220257604051635d9515b960e11b815260040160405180910390fd5b604051633ee83b9960e21b81526001600160a01b0387169063fba0ee64906122389030908990899089908990899060040161555a565b600060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b50505050505050505050565b606080600061228761203d60208601866154ee565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb91906154d1565b6001600160a01b031661230160208601866154ee565b6001600160a01b0316146123285760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661235f60208601866154ee565b6001600160a01b03161480156123785750348460600135145b156123a6576123878134612eaa565b6123a13382608087013561210f6040890160208a016154ee565b61213a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166123e060408601602087016154ee565b6001600160a01b03161480156123f95750348460800135145b1561241f576124153382606087013561210f60208901896154ee565b6123a18134612eaa565b61242c60208501856154ee565b61243c60408601602087016154ee565b60405163959ceb2b60e01b81526001600160a01b03928316600482015291166024820152606085013560448201526080850135606482015234608482015260a401610733565b600061201f82846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190615330565b5161ffff166140ed565b600081804211156125225760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b858581516000148061254157508051825161253e906001615456565b14155b1561255f5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168789518151811061259c5761259c6154a2565b60200260200101516001600160a01b0316146125c55786885181518110610b2757610b276154a2565b60006125d18989612889565b90506125ea338260008151811061163a5761163a6154a2565b6125f78b828b8b30612f59565b9450848a1115612624576040516313fab00360e21b8152600481018b905260248101869052604401610733565b604051632e1a7d4d60e01b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561268657600080fd5b505af115801561269a573d6000803e3d6000fd5b505050506116908786613894565b600082610160015164ffffffffff16426126c2919061546e565b9050826040015161ffff16811015806126e5575061016083015164ffffffffff16155b156127455762ffffff8216610140840152606083015161ffff1681101561273c5761271083610100015162ffffff16846080015161ffff16028161272b5761272b6155a7565b0462ffffff16610120840152612745565b60006101208401525b61274e42614153565b64ffffffffff1661016084015261146683836139c7565b60408051808201909152600080825260208201819052908190600061279287896000015161ffff1661391a565b905060008087156127c05760208b01516001600160701b031691506127b982608085613995565b90506127dc565b8a516001600160701b031691506127d983836080613962565b90505b6127e68a8a6139c7565b6127fa6127f38b83613a39565b8b90614183565b80519094508790612814906001600160801b031683615456565b116128245780955081945061287b565b6128316127f38b896141cf565b8051909450612849906001600160801b03168861546e565b9550876128615761285c86608085614216565b61286d565b61286d83876080614263565b94508185111561287b578194505b505050955095509592505050565b6060825167ffffffffffffffff8111156128a5576128a5614c0b565b6040519080825280602002602001820160405280156128ce578160200160208202803683370190505b509050600080836000815181106128e7576128e76154a2565b6020026020010151905060005b835181101561297557819250848160010181518110612915576129156154a2565b60200260200101519150612943868281518110612934576129346154a2565b602002602001015184846142f2565b848281518110612955576129556154a2565b6001600160a01b03909216602092830291909101909101526001016128f4565b50505092915050565b8015612a3957604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905260006129f486836143de565b905060008151118015612a18575080806020019051810190612a1691906155bd565b155b15612a365760405163197138bd60e11b815260040160405180910390fd5b50505b50505050565b600080600080600086600081518110612a5a57612a5a6154a2565b6020026020010151905060005b895181101561226657898181518110612a8257612a826154a2565b60200260200101519250888181518110612a9e57612a9e6154a2565b60200260200101519450819550878160010181518110612ac057612ac06154a2565b6020026020010151915089518160010114612af757898160010181518110612aea57612aea6154a2565b6020026020010151612af9565b865b935084612da157600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6591906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015612c9a576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0591906154b8565b0390506000612c158285856144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612c7b57600080fd5b505af1158015612c8f573d6000803e3d6000fd5b505050505050612d9a565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0991906154b8565b0390506000612d198284866144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612d7f57600080fd5b505af1158015612d93573d6000803e3d6000fd5b5050505050505b5050612ea2565b826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1291906154d1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af1158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9f919061541c565b50505b600101612a67565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0557600080fd5b505af1158015612f19573d6000803e3d6000fd5b50612f559350506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915084905083613a89565b5050565b60008060008060008087600081518110612f7557612f756154a2565b602002602001015190508a955060005b8a5181101561102e578a8181518110612fa057612fa06154a2565b60200260200101519250898181518110612fbc57612fbc6154a2565b60200260200101519450819550888160010181518110612fde57612fde6154a2565b602002602001015191508a518160010114613015578a8160010181518110613008576130086154a2565b6020026020010151613017565b875b9350846131d357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561305f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308391906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613142576130bf8983836144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561312557600080fd5b505af1158015613139573d6000803e3d6000fd5b505050506131cc565b61314d8982846144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156131b357600080fd5b505af11580156131c7573d6000803e3d6000fd5b505050505b50506132d2565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323791906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af1158015613294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b8919061541c565b9150915082156132ca578099506132ce565b8199505b5050505b600101612f85565b6060825167ffffffffffffffff8111156132f6576132f6614c0b565b60405190808252806020026020018201604052801561331f578160200160208202803683370190505b5090508181855181518110613336576133366154a2565b602090810291909101015283515b80156135bc5760008461335860018461546e565b81518110613368576133686154a2565b60200260200101519050600087600184613382919061546e565b81518110613392576133926154a2565b602002602001015190506000876001856133ac919061546e565b815181106133bc576133bc6154a2565b6020026020010151905081600014156134e357600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343491906155f1565b506001600160701b031691506001600160701b0316915088868151811061345d5761345d6154a2565b60200260200101516001600160a01b0316856001600160a01b0316111561348057905b6000878781518110613494576134946154a2565b602002602001015190506134b38383836145409092919063ffffffff16565b886134bf60018a61546e565b815181106134cf576134cf6154a2565b6020026020010181815250505050506135a6565b61357c818686815181106134f9576134f96154a2565b6020026020010151856001600160a01b0316846001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356d91906154d1565b6001600160a01b03161461103d565b508561358960018761546e565b81518110613599576135996154a2565b6020026020010181815250505b50505080806135b490615636565b915050613344565b50949350505050565b600080600080600080886000815181106135e1576135e16154a2565b6020026020010151905060005b8b5181101561102e578b8181518110613609576136096154a2565b602002602001015192508a8181518110613625576136256154a2565b60200260200101519450819550898160010181518110613647576136476154a2565b602002602001015191508b51816001011461367e578b8160010181518110613671576136716154a2565b6020026020010151613680565b875b93508461378d5788816001018151811061369c5761369c6154a2565b60200260200101519650816001600160a01b0316866001600160a01b031610156137405760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a4015b600060405180830381600087803b15801561372357600080fd5b505af1158015613737573d6000803e3d6000fd5b5050505061388c565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a401613709565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f191906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af115801561384e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613872919061541c565b91509150821561388457809950613888565b8199505b5050505b6001016135ee565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146138e1576040519150601f19603f3d011682016040523d82523d6000602084013e6138e6565b606091505b505090508061146657604051631722e2bb60e21b81526001600160a01b038416600482015260248101839052604401610733565b600062ffffff8311156139405760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161395a81613954856145d2565b90614618565b949350505050565b600061396f848484614263565b90506001821b80613982576139826155a7565b8385091561398e576001015b9392505050565b60006139a2848484614216565b905081806139b2576139b26155a7565b6001841b85091561398e576001019392505050565b600082610120015162ffffff166127106139f485610140015162ffffff168561487190919063ffffffff16565b6139fe919061564d565b613a089190615456565b90508260e0015162ffffff168111613a205780613a26565b8260e001515b62ffffff16610100909301929092525050565b600080613a4584614888565b90506000613a5b82670de0b6b3a764000061546e565b905080600181613a6b858861564d565b613a759190615456565b613a7f919061546e565b6115a2919061566c565b801561146657604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526000613af785836143de565b905060008151118015613b1b575080806020019051810190613b1991906155bd565b155b15613b395760405163197138bd60e11b815260040160405180910390fd5b5050505050565b60405163704037bd60e01b81526001600160a01b03848116600483015283811660248301526044820183905260009182917f0000000000000000000000000000000000000000000000000000000000000000169063704037bd90606401608060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde919061568e565b6020015190506001600160a01b03811661395a57604051636b2471d160e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610733565b600080876001600160a01b031663fba0ee64338a88886040518563ffffffff1660e01b8152600401613c5a9493929190615713565b600060405180830381600087803b158015613c7457600080fd5b505af1158015613c88573d6000803e3d6000fd5b5050604051630acd451d60e01b81526001600160a01b038b169250630acd451d9150613cbc90889088908890600401615751565b60408051808303816000875af1158015613cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfe919061541c565b909250905086821080613d1057508581105b15613d46576040516318ccfb7760e11b815260048101889052602481018390526044810187905260648101829052608401610733565b965096945050505050565b606080836101a0013580421115613d845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b613d92610140860186615790565b9050613da2610120870187615790565b905014158015613dd05750613dbb610160860186615790565b9050613dcb610120870187615790565b905014155b15613dee5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08601351180613e0a575062ffffff610100860135115b15613e395760405163197a55c760e11b815260e086013560048201526101008601356024820152604401610733565b6000846001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9d91906152d7565b92505050808661010001358760e00135011080613ec457508560e001358661010001358201105b15613efa57604051637d50edab60e11b815260e08701356004820152610100870135602482015260448101829052606401610733565b613f08610120870187615790565b905067ffffffffffffffff811115613f2257613f22614c0b565b604051908082528060200260200182016040528015613f4b578160200160208202803683370190505b50935060005b8451811015613fde576000613f6a610120890189615790565b83818110613f7a57613f7a6154a2565b90506020020135830190506000811280613f96575062ffffff81115b15613fb7576040516370a82e6160e11b815260048101829052602401610733565b80868381518110613fca57613fca6154a2565b602090810291909101015250600101613f51565b506000806001600160a01b03871663714c8592876140006101408c018c615790565b61400e6101608e018e615790565b8e61018001602081019061402291906154ee565b6040518763ffffffff1660e01b8152600401614043969594939291906157da565b6000604051808303816000875af1158015614062573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261408a9190810190615832565b9650909250905060a08801358210806140a657508760c0013581105b156140e2576040516318ccfb7760e11b815260a089013560048201526024810183905260c0890135604482015260648101829052608401610733565b505050509250929050565b6000806140f9836145d2565b90506000614106826148b1565b61410f866148b1565b8161411c5761411c6155a7565b05628000000190506000811280614135575062ffffff81115b1561395a5760405163163d8bab60e21b815260040160405180910390fd5b8064ffffffffff8116811461417e576040516302dfd99760e01b815260048101839052602401610733565b919050565b60408051808201909152600080825260208201526141a0826149bc565b6001600160801b0316815260c08301516127109061ffff168302046001600160801b0316602082015292915050565b6000670de0b6b3a76400006001670de0b6b3a76400006141ee86614888565b6141f8908661564d565b6142029190615456565b61420c919061546e565b61201f919061566c565b600060ff83111561423d57604051630b72ecf560e41b815260048101849052602401610733565b83831b61010084900385901c614259866001871b8685856149e9565b9695505050505050565b600060ff82111561428a57604051630b72ecf560e41b815260048101839052602401610733565b6000806142978686614a9c565b91509150816000146142a95781841c92505b80156142e9576001841b81106142dc57604051633d90990f60e01b81526004810182905260248101859052604401610733565b836101000381901b830192505b50509392505050565b6000836143d35760405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e6a4390590604401602060405180830381865afa158015614367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438b91906154d1565b90506001600160a01b0381166143ce57604051636b2471d160e11b81526001600160a01b0380851660048301528316602482015260448101859052606401610733565b61398e565b61395a838386613b40565b6060600080846001600160a01b0316846040516143fb91906158d8565b6000604051808303816000865af19150503d8060008114614438576040519150601f19603f3d011682016040523d82523d6000602084013e61443d565b606091505b5091509150811561448257805115801561445f57506001600160a01b0385163b155b1561447d57604051635d97df8960e01b815260040160405180910390fd5b61395a565b80516144a157604051632407429160e01b815260040160405180910390fd5b805181602001fd5b6000836144c95760405163b229ed3360e01b815260040160405180910390fd5b8215806144d4575081155b156144f2576040516398c59a2960e01b815260040160405180910390fd5b6000614500856103e561564d565b9050600061450e848361564d565b905060008261451f876103e861564d565b6145299190615456565b9050614535818361566c565b979650505050505050565b6000836145605760405163b229ed3360e01b815260040160405180910390fd5b82158061456b575081155b15614589576040516398c59a2960e01b815260040160405180910390fd5b6000614595858561564d565b6145a1906103e861564d565b905060006145af868561546e565b6145bb906103e561564d565b90506145c7818361566c565b614259906001615456565b60008115806145e2575061271082115b15614603576040516374da1e1160e11b815260048101839052602401610733565b612710608083901b04600160801b0192915050565b60008080836146305750600160801b91506120229050565b50826000811215614642579015906000035b6210000081101561483257600160801b9250846001600160801b0381111561466c57911591600019045b600182161561467d5792830260801c925b800260801c60028216156146935792830260801c925b800260801c60048216156146a95792830260801c925b800260801c60088216156146bf5792830260801c925b800260801c60108216156146d55792830260801c925b800260801c60208216156146eb5792830260801c925b800260801c60408216156147015792830260801c925b8002608090811c908216156147185792830260801c925b800260801c61010082161561472f5792830260801c925b800260801c6102008216156147465792830260801c925b800260801c61040082161561475d5792830260801c925b800260801c6108008216156147745792830260801c925b800260801c61100082161561478b5792830260801c925b800260801c6120008216156147a25792830260801c925b800260801c6140008216156147b95792830260801c925b800260801c6180008216156147d05792830260801c925b800260801c620100008216156147e85792830260801c925b800260801c620200008216156148005792830260801c925b800260801c620400008216156148185792830260801c925b800260801c620800008216156148305792830260801c925b505b8261485a57604051630e9c7d6160e31b81526004810186905260248101859052604401610733565b8161486557826115a2565b6115a28360001961566c565b60008183116148825782820361201f565b50900390565b600061489382614abb565b8251602084015161ffff9182169116026402540be400020192915050565b600081600114156148c55750607f19919050565b816148e3576040516304c9fcb960e01b815260040160405180910390fd5b60019190911c9060006f80000000000000000000000000000000831061490b57506001614926565b5060001982600160fe1b81614922576149226155a7565b0492505b6000614935607f85901c614b0f565b707f80000000000000000000000000000000607f82901b16935060ff16905083811c6f8000000000000000000000000000000081146149b1576f400000000000000000000000000000005b60008113156149af57908002607f1c90600160801b82106149a7579384019360019190911c905b60011d614980565b505b50500260011b919050565b806001600160801b038116811461417e5760405163089f6cfb60e21b815260048101839052602401610733565b600081614a07578383816149ff576149ff6155a7565b0490506115a2565b838210614a315760405163656b542b60e11b81526004810183905260248101859052604401610733565b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b60008160a0015162ffffff1660001461417e576000826000015161ffff1683610100015162ffffff1602905060648360a0015162ffffff168283020260630181614b0757614b076155a7565b049392505050565b6000600160801b8210614b245750608090811c905b680100000000000000008210614b3c57604091821c91015b6401000000008210614b5057602091821c91015b620100008210614b6257601091821c91015b6101008210614b7357600891821c91015b60108210614b8357600491821c91015b60048210614b9357600291821c91015b6002821061417e57600101919050565b6001600160a01b0381168114614bb857600080fd5b50565b8015158114614bb857600080fd5b600080600060608486031215614bde57600080fd5b8335614be981614ba3565b9250602084013591506040840135614c0081614bbb565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614c4557614c45614c0b565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614c7457614c74614c0b565b604052919050565b600067ffffffffffffffff821115614c9657614c96614c0b565b5060051b60200190565b600082601f830112614cb157600080fd5b81356020614cc6614cc183614c7c565b614c4b565b82815260059290921b84018101918181019086841115614ce557600080fd5b8286015b84811015614d005780358352918301918301614ce9565b509695505050505050565b803561417e81614ba3565b600082601f830112614d2757600080fd5b81356020614d37614cc183614c7c565b82815260059290921b84018101918181019086841115614d5657600080fd5b8286015b84811015614d00578035614d6d81614ba3565b8352918301918301614d5a565b60008060008060008060c08789031215614d9357600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614db957600080fd5b614dc58a838b01614ca0565b95506060890135915080821115614ddb57600080fd5b50614de889828a01614d16565b9350506080870135614df981614ba3565b8092505060a087013590509295509295509295565b600080600080600060a08688031215614e2657600080fd5b85359450602086013567ffffffffffffffff80821115614e4557600080fd5b614e5189838a01614ca0565b95506040880135915080821115614e6757600080fd5b50614e7488828901614d16565b9350506060860135614e8581614ba3565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015614ec657815187529582019590820190600101614eaa565b509495945050505050565b60208152600061201f6020830184614e96565b600080600060608486031215614ef957600080fd5b8335614f0481614ba3565b92506020840135614f1481614ba3565b929592945050506040919091013590565b62ffffff81168114614bb857600080fd5b61ffff81168114614bb857600080fd5b803561417e81614f36565b60008060008060808587031215614f6757600080fd5b8435614f7281614ba3565b93506020850135614f8281614ba3565b92506040850135614f9281614f25565b91506060850135614fa281614f36565b939692955090935050565b600080600080600080600080610100898b031215614fca57600080fd5b8835614fd581614ba3565b97506020890135614fe581614f36565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561501057600080fd5b61501c8c838d01614ca0565b955060a08b013591508082111561503257600080fd5b5061503f8b828c01614ca0565b93505060c089013561505081614ba3565b8092505060e089013590509295985092959890939650565b60008060008060008060008060006101208a8c03121561508757600080fd5b893561509281614ba3565b985060208a01356150a281614ba3565b97506150b060408b01614f46565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff808211156150db57600080fd5b6150e78d838e01614ca0565b955060c08c01359150808211156150fd57600080fd5b5061510a8c828d01614ca0565b93505061511960e08b01614d0b565b91506101008a013590509295985092959850929598565b6000806040838503121561514357600080fd5b823561514e81614ba3565b9150602083013561515e81614f25565b809150509250929050565b60006020828403121561517b57600080fd5b813567ffffffffffffffff81111561519257600080fd5b82016101c0818503121561398e57600080fd5b6040815260006151b86040830185614e96565b82810360208401526115a28185614e96565b60008083601f8401126151dc57600080fd5b50813567ffffffffffffffff8111156151f457600080fd5b6020830191508360208260051b850101111561520f57600080fd5b9250929050565b6000806000806000806080878903121561522f57600080fd5b863561523a81614ba3565b9550602087013561524a81614ba3565b9450604087013567ffffffffffffffff8082111561526757600080fd5b6152738a838b016151ca565b9096509450606089013591508082111561528c57600080fd5b5061529989828a016151ca565b979a9699509497509295939492505050565b600080604083850312156152be57600080fd5b82356152c981614ba3565b946020939093013593505050565b6000806000606084860312156152ec57600080fd5b8351925060208401519150604084015190509250925092565b805161417e81614f36565b805161417e81614f25565b805164ffffffffff8116811461417e57600080fd5b6000610180828403121561534357600080fd5b61534b614c21565b61535483615305565b815261536260208401615305565b602082015261537360408401615305565b604082015261538460608401615305565b606082015261539560808401615305565b60808201526153a660a08401615310565b60a08201526153b760c08401615305565b60c08201526153c860e08401615310565b60e08201526101006153db818501615310565b908201526101206153ed848201615310565b908201526101406153ff848201615310565b9082015261016061541184820161531b565b908201529392505050565b6000806040838503121561542f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b6000821982111561546957615469615440565b500190565b60008282101561548057615480615440565b500390565b60006020828403121561549757600080fd5b815161398e81614f25565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ca57600080fd5b5051919050565b6000602082840312156154e357600080fd5b815161398e81614ba3565b60006020828403121561550057600080fd5b813561398e81614ba3565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561553d57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60006001600160a01b0380891683528088166020840152506080604083015261558760808301868861550b565b828103606084015261559a81858761550b565b9998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602082840312156155cf57600080fd5b815161398e81614bbb565b80516001600160701b038116811461417e57600080fd5b60008060006060848603121561560657600080fd5b61560f846155da565b925061561d602085016155da565b9150604084015163ffffffff81168114614c0057600080fd5b60008161564557615645615440565b506000190190565b600081600019048311821515161561566757615667615440565b500290565b60008261568957634e487b7160e01b600052601260045260246000fd5b500490565b6000608082840312156156a057600080fd5b6040516080810181811067ffffffffffffffff821117156156c3576156c3614c0b565b60405282516156d181614f36565b815260208301516156e181614ba3565b602082015260408301516156f481614bbb565b6040820152606083015161570781614bbb565b60608201529392505050565b60006001600160a01b0380871683528086166020840152506080604083015261573f6080830185614e96565b82810360608401526145358185614e96565b6060815260006157646060830186614e96565b82810360208401526157768186614e96565b9150506001600160a01b0383166040830152949350505050565b6000808335601e198436030181126157a757600080fd5b83018035915067ffffffffffffffff8211156157c257600080fd5b6020019150600581901b360382131561520f57600080fd5b6080815260006157ed6080830189614e96565b828103602084015261580081888a61550b565b9050828103604084015261581581868861550b565b9150506001600160a01b0383166060830152979650505050505050565b60008060006060848603121561584757600080fd5b835192506020808501519250604085015167ffffffffffffffff81111561586d57600080fd5b8501601f8101871361587e57600080fd5b805161588c614cc182614c7c565b81815260059190911b820183019083810190898311156158ab57600080fd5b928401925b828410156158c9578351825292840192908401906158b0565b80955050505050509250925092565b6000825160005b818110156158f957602081860181015185830152016158df565b81811115615908576000828501525b50919091019291505056fea26469706673582212206c05eee95a8862d596ac1d3ea3c231cfdc4a1453951fddb1394e8ead624c932964736f6c634300080a00330000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7

-----Decoded View---------------
Arg [0] : _factory (address): 0x6e77932a92582f504ff6c4bdbcef7da6c198aeef
Arg [1] : _oldFactory (address): 0x9ad6c38be94206ca50bb0d90783181662f0cfa10
Arg [2] : _wavax (address): 0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef
Arg [1] : 0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10
Arg [2] : 000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.