MNT Price: $0.86 (+1.54%)

Contract

0xB6c2f11a656C0c1Ae71C392cf3b7897af900B638
 

Overview

MNT Balance

Mantle Mainnet Network LogoMantle Mainnet Network LogoMantle Mainnet Network Logo0 MNT

MNT Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

> 10 Token Transfers found.

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniversalSwapHelper

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

import {IBaseSwapHelper} from '../../interfaces/helper/swap_helper/IBaseSwapHelper.sol';
import {SwapInfo, SwapType} from '../../interfaces/hook/IMarginTradingHook.sol';

import {IMoeRouter} from '../../interfaces/common/moe/IMoeRouter.sol';
import {IAgniSwapRouter} from '../../interfaces/common/agni/IAgniSwapRouter.sol';
import {IFusionXSwapRouter} from '../../interfaces/common/fusionx/IFusionXSwapRouter.sol';
import {ILBRouter} from '../../interfaces/common/moe_v2/ILBRouter.sol';

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol';

contract UniversalSwapHelper is IBaseSwapHelper {
    using SafeERC20 for IERC20;

    address public constant MOE_ROUTER = 0xeaEE7EE68874218c3558b40063c42B82D3E7232a;
    address public constant AGNI_ROUTER = 0x319B69888b0d11cEC22caA5034e25FfFBDc88421;
    address public constant FUSIONX_ROUTER = 0x5989FB161568b9F133eDf5Cf6787f5597762797F;
    address public constant MOE_LB_ROUTER = 0xAFb85a12Babfafabfe1a518594492d5a830e782a;

    function swap(SwapInfo calldata _swapInfo) external {
        (address router, bytes memory swapData) = abi.decode(_swapInfo.data, (address, bytes));
        if (router == MOE_ROUTER) {
            _swapMoe(_swapInfo, swapData);
        } else if (router == AGNI_ROUTER) {
            _swapAgni(_swapInfo, swapData);
        } else if (router == FUSIONX_ROUTER) {
            _swapFusionX(_swapInfo, swapData);
        } else if (router == MOE_LB_ROUTER) {
            _swapMoeLB(_swapInfo, swapData);
        } else {
            revert('invalid input');
        }
        _refund(_swapInfo.tokenIn);
    }

    function _refund(address _token) internal {
        uint balance = IERC20(_token).balanceOf(address(this));
        if (balance > 0) IERC20(_token).safeTransfer(msg.sender, balance);
    }

    function _ensureApprove(address _token, address _router, uint _amt) internal {
        if (IERC20(_token).allowance(address(this), _router) < _amt) {
            IERC20(_token).safeApprove(_router, type(uint).max);
        }
    }

    function _swapMoe(SwapInfo calldata _swapInfo, bytes memory _swapData) internal {
        (address[] memory path, uint deadline) = abi.decode(_swapData, (address[], uint));
        uint balance = IERC20(_swapInfo.tokenIn).balanceOf(address(this));
        // approve token in for router
        _ensureApprove(_swapInfo.tokenIn, MOE_ROUTER, balance);
        if (_swapInfo.swapType == SwapType.CloseExactOut) {
            IMoeRouter(MOE_ROUTER).swapTokensForExactTokens(_swapInfo.amtOut, balance, path, msg.sender, deadline);
        } else {
            // note: msg.sender should check amtOut
            IMoeRouter(MOE_ROUTER).swapExactTokensForTokens(balance, _swapInfo.amtOut, path, msg.sender, deadline);
        }
    }

    function _swapAgni(SwapInfo calldata _swapInfo, bytes memory _swapData) internal {
        (bytes memory path, uint deadline) = abi.decode(_swapData, (bytes, uint));
        uint balance = IERC20(_swapInfo.tokenIn).balanceOf(address(this));
        // approve token in for router
        _ensureApprove(_swapInfo.tokenIn, AGNI_ROUTER, balance);
        if (_swapInfo.swapType == SwapType.CloseExactOut) {
            IAgniSwapRouter(AGNI_ROUTER).exactOutput(
                IAgniSwapRouter.ExactOutputParams({
                    path: path,
                    recipient: msg.sender,
                    deadline: deadline,
                    amountOut: _swapInfo.amtOut,
                    amountInMaximum: balance
                })
            );
        } else {
            // note: msg.sender should check amtOut
            IAgniSwapRouter(AGNI_ROUTER).exactInput(
                IAgniSwapRouter.ExactInputParams({
                    path: path,
                    recipient: msg.sender,
                    deadline: deadline,
                    amountIn: balance,
                    amountOutMinimum: _swapInfo.amtOut
                })
            );
        }
    }

    function _swapFusionX(SwapInfo calldata _swapInfo, bytes memory _swapData) internal {
        (bytes memory path, uint deadline) = abi.decode(_swapData, (bytes, uint));
        uint balance = IERC20(_swapInfo.tokenIn).balanceOf(address(this));
        // approve token in for router
        _ensureApprove(_swapInfo.tokenIn, FUSIONX_ROUTER, balance);
        if (_swapInfo.swapType == SwapType.CloseExactOut) {
            IFusionXSwapRouter(FUSIONX_ROUTER).exactOutput(
                IFusionXSwapRouter.ExactOutputParams({
                    path: path,
                    recipient: msg.sender,
                    deadline: deadline,
                    amountOut: _swapInfo.amtOut,
                    amountInMaximum: balance
                })
            );
        } else {
            // note: msg.sender should check amtOut
            IFusionXSwapRouter(FUSIONX_ROUTER).exactInput(
                IFusionXSwapRouter.ExactInputParams({
                    path: path,
                    recipient: msg.sender,
                    deadline: deadline,
                    amountIn: balance,
                    amountOutMinimum: _swapInfo.amtOut
                })
            );
        }
    }

    function _swapMoeLB(SwapInfo calldata _swapInfo, bytes memory _swapData) internal {
        (ILBRouter.Path memory path, uint deadline) = abi.decode(_swapData, (ILBRouter.Path, uint));
        uint balance = IERC20(_swapInfo.tokenIn).balanceOf(address(this));
        // approve token in for router
        _ensureApprove(_swapInfo.tokenIn, MOE_LB_ROUTER, balance);
        if (_swapInfo.swapType == SwapType.CloseExactOut) {
            ILBRouter(MOE_LB_ROUTER).swapTokensForExactTokens(_swapInfo.amtOut, balance, path, msg.sender, deadline);
        } else {
            // note: msg.sender should check amtOut
            ILBRouter(MOE_LB_ROUTER).swapExactTokensForTokens(balance, _swapInfo.amtOut, path, msg.sender, deadline);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/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);
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

/// @title Wrapped Native Interface
interface IWNative is IERC20 {
    /// @dev wrap the native token to wrapped token using `msg.value` as the amount
    function deposit() external payable;

    /// @dev unwrap the wrapped token to native token
    /// @param amount token amount to unwrap
    function withdraw(uint amount) external;
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

/// @title Wrapped Native Interface
interface IWNative is IERC20 {
    /// @dev wrap the native token to wrapped token using `msg.value` as the amount
    function deposit() external payable;

    /// @dev unwrap the wrapped token to native token
    /// @param amount token amount to unwrap
    function withdraw(uint amount) external;
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

interface IAgniSwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint deadline;
        uint amountIn;
        uint amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint deadline;
        uint amountIn;
        uint amountOutMinimum;
    }

    function exactInput(ExactInputParams calldata params) external payable returns (uint amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint deadline;
        uint amountOut;
        uint amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint deadline;
        uint amountOut;
        uint amountInMaximum;
    }

    function exactOutput(ExactOutputParams calldata params) external payable returns (uint amountIn);
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

interface IFusionXSwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint deadline;
        uint amountIn;
        uint amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint deadline;
        uint amountIn;
        uint amountOutMinimum;
    }

    function exactInput(ExactInputParams calldata params) external payable returns (uint amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint deadline;
        uint amountOut;
        uint amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint deadline;
        uint amountOut;
        uint amountInMaximum;
    }

    function exactOutput(ExactOutputParams calldata params) external payable returns (uint amountIn);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

interface IMoeRouter {
    function factory() external view returns (address);

    function wNative() external view returns (address);

    function pairImplementation() external view returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);

    function addLiquidityNative(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountNativeMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountNative, uint liquidity);

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);

    function removeLiquidityNative(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountNativeMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountNative);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountA, uint amountB);

    function removeLiquidityNativeWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountNativeMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountToken, uint amountNative);

    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapExactNativeForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function swapTokensForExactNative(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapExactTokensForNative(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapNativeForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);

    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);

    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);

    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);

    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);

    function removeLiquidityNativeSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountNativeMin,
        address to,
        uint deadline
    ) external returns (uint amountNative);

    function removeLiquidityNativeWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountNativeMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountNative);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;

    function swapExactNativeForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;

    function swapExactTokensForNativeSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

// 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, uint);

    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(uint) external view returns (address pair);

    function allPairsLength() external view returns (uint);

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

    function setFeeTo(address) external;

    function setFeeToSetter(address) external;

    function setMigrator(address) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {ILBPair} from './ILBPair.sol';
import {IPendingOwnable} from './IPendingOwnable.sol';

/**
 * @title Liquidity Book Factory Interface
 * @author Trader Joe
 * @notice Required interface of LBFactory contract
 */
interface ILBFactory is IPendingOwnable {
    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, uint _binStep);
    error LBFactory__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint binStep);
    error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint binStep);
    error LBFactory__FlashLoanFeeAboveMax(uint fees, uint maxFees);
    error LBFactory__BinStepTooLow(uint binStep);
    error LBFactory__PresetIsLockedForUsers(address user, uint binStep);
    error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
    error LBFactory__BinStepHasNoPreset(uint binStep);
    error LBFactory__PresetOpenStateIsAlreadyInTheSameState();
    error LBFactory__SameFeeRecipient(address feeRecipient);
    error LBFactory__SameFlashLoanFee(uint flashLoanFee);
    error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
    error LBFactory__SameImplementation(address LBPairImplementation);
    error LBFactory__ImplementationNotSet();

    /**
     * @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, uint indexed binStep, ILBPair LBPair, uint pid);

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint oldFlashLoanFee, uint newFlashLoanFee);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored);

    event PresetSet(
        uint indexed binStep,
        uint baseFactor,
        uint filterPeriod,
        uint decayPeriod,
        uint reductionFactor,
        uint variableFeeControl,
        uint protocolShare,
        uint maxVolatilityAccumulator
    );

    event PresetOpenStateChanged(uint indexed binStep, bool indexed isOpen);

    event PresetRemoved(uint indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function getMinBinStep() external pure returns (uint);

    function getFeeRecipient() external view returns (address);

    function getMaxFlashLoanFee() external pure returns (uint);

    function getFlashLoanFee() external view returns (uint);

    function getLBPairImplementation() external view returns (address);

    function getNumberOfLBPairs() external view returns (uint);

    function getLBPairAtIndex(uint id) external returns (ILBPair);

    function getNumberOfQuoteAssets() external view returns (uint);

    function getQuoteAssetAtIndex(uint index) external view returns (IERC20);

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

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

    function getPreset(uint binStep)
        external
        view
        returns (
            uint baseFactor,
            uint filterPeriod,
            uint decayPeriod,
            uint reductionFactor,
            uint variableFeeControl,
            uint protocolShare,
            uint maxAccumulator,
            bool isOpen
        );

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

    function getOpenBinSteps() external view returns (uint[] memory openBinStep);

    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, uint16 binStep, bool ignored) external;

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        bool isOpen
    ) external;

    function setPresetOpenState(uint16 binStep, bool isOpen) 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 maxVolatilityAccumulator
    ) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint flashLoanFee) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBPair lbPair) external;
}

File 14 of 24 : ILBFlashLoanCallback.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/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 tokenX,
        IERC20 tokenY,
        bytes32 amounts,
        bytes32 totalFees,
        bytes calldata data
    ) external returns (bytes32);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {ILBLegacyPair} from './ILBLegacyPair.sol';
import {IPendingOwnable} from './IPendingOwnable.sol';

/// @title Liquidity Book Factory Interface
/// @author Trader Joe
/// @notice Required interface of LBFactory contract
interface ILBLegacyFactory 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;
        ILBLegacyPair LBPair;
        bool createdByOwner;
        bool ignoredForRouting;
    }

    event LBPairCreated(
        IERC20 indexed tokenX, IERC20 indexed tokenY, uint indexed binStep, ILBLegacyPair LBPair, uint pid
    );

    event FeeRecipientSet(address oldRecipient, address newRecipient);

    event FlashLoanFeeSet(uint oldFlashLoanFee, uint newFlashLoanFee);

    event FeeParametersSet(
        address indexed sender,
        ILBLegacyPair indexed LBPair,
        uint binStep,
        uint baseFactor,
        uint filterPeriod,
        uint decayPeriod,
        uint reductionFactor,
        uint variableFeeControl,
        uint protocolShare,
        uint maxVolatilityAccumulator
    );

    event FactoryLockedStatusUpdated(bool unlocked);

    event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);

    event LBPairIgnoredStateChanged(ILBLegacyPair indexed LBPair, bool ignored);

    event PresetSet(
        uint indexed binStep,
        uint baseFactor,
        uint filterPeriod,
        uint decayPeriod,
        uint reductionFactor,
        uint variableFeeControl,
        uint protocolShare,
        uint maxVolatilityAccumulator,
        uint sampleLifetime
    );

    event PresetRemoved(uint indexed binStep);

    event QuoteAssetAdded(IERC20 indexed quoteAsset);

    event QuoteAssetRemoved(IERC20 indexed quoteAsset);

    function MAX_FEE() external pure returns (uint);

    function MIN_BIN_STEP() external pure returns (uint);

    function MAX_BIN_STEP() external pure returns (uint);

    function MAX_PROTOCOL_SHARE() external pure returns (uint);

    function LBPairImplementation() external view returns (address);

    function getNumberOfQuoteAssets() external view returns (uint);

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

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

    function feeRecipient() external view returns (address);

    function flashLoanFee() external view returns (uint);

    function creationUnlocked() external view returns (bool);

    function allLBPairs(uint id) external returns (ILBLegacyPair);

    function getNumberOfLBPairs() external view returns (uint);

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

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

    function getAllBinSteps() external view returns (uint[] 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 (ILBLegacyPair pair);

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

    function setPreset(
        uint16 binStep,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        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 maxVolatilityAccumulator
    ) external;

    function setFeeRecipient(address feeRecipient) external;

    function setFlashLoanFee(uint flashLoanFee) external;

    function setFactoryLockedState(bool locked) external;

    function addQuoteAsset(IERC20 quoteAsset) external;

    function removeQuoteAsset(IERC20 quoteAsset) external;

    function forceDecay(ILBLegacyPair LBPair) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {ILBLegacyToken} from './ILBLegacyToken.sol';

/// @title Liquidity Book Pair V2 Interface
/// @author Trader Joe
/// @notice Required interface of LBPair contract
interface ILBLegacyPair is ILBLegacyToken {
    /// @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;
    }

    /// @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;
        uint accTokenXPerShare;
        uint 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;
        FeesDistribution feesX;
        FeesDistribution feesY;
    }

    /// @dev Structure to store the debts of users
    /// - debtX: The tokenX's debt
    /// - debtY: The tokenY's debt
    struct Debts {
        uint debtX;
        uint 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 {
        uint amountXIn;
        uint amountYIn;
        uint amountXAddedToPair;
        uint amountYAddedToPair;
        uint activeFeeX;
        uint activeFeeY;
        uint totalDistributionX;
        uint totalDistributionY;
        uint id;
        uint amountX;
        uint amountY;
        uint distributionX;
        uint distributionY;
    }

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

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

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

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

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

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

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

    event OracleSizeIncreased(uint previousSize, uint newSize);

    function tokenX() external view returns (IERC20);

    function tokenY() external view returns (IERC20);

    function factory() external view returns (address);

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

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

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

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

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

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

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

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

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

    function flashLoan(address receiver, IERC20 token, uint amount, bytes calldata data) external;

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

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

    function increaseOracleLength(uint16 newSize) external;

    function collectFees(address account, uint[] calldata ids) external returns (uint amountX, uint 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;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {ILBFactory} from './ILBFactory.sol';
import {IJoeFactory} from './IJoeFactory.sol';
import {ILBLegacyPair} from './ILBLegacyPair.sol';
import {ILBToken} from './ILBToken.sol';
import {IWNative} from '../IWNative.sol';

/// @title Liquidity Book Router Interface
/// @author Trader Joe
/// @notice Required interface of LBRouter contract
interface ILBLegacyRouter {
    struct LiquidityParameters {
        IERC20 tokenX;
        IERC20 tokenY;
        uint binStep;
        uint amountX;
        uint amountY;
        uint amountXMin;
        uint amountYMin;
        uint activeIdDesired;
        uint idSlippage;
        int[] deltaIds;
        uint[] distributionX;
        uint[] distributionY;
        address to;
        uint deadline;
    }

    function factory() external view returns (address);

    function wavax() external view returns (address);

    function oldFactory() external view returns (address);

    function getIdFromPrice(ILBLegacyPair LBPair, uint price) external view returns (uint24);

    function getPriceFromId(ILBLegacyPair LBPair, uint24 id) external view returns (uint);

    function getSwapIn(ILBLegacyPair lbPair, uint amountOut, bool swapForY)
        external
        view
        returns (uint amountIn, uint feesIn);

    function getSwapOut(ILBLegacyPair lbPair, uint amountIn, bool swapForY)
        external
        view
        returns (uint amountOut, uint feesIn);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import '@openzeppelin-contracts/utils/introspection/IERC165.sol';

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

    event TransferBatch(address indexed sender, address indexed from, address indexed to, uint[] ids, uint[] 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, uint id) external view returns (uint);

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

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

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

    function setApprovalForAll(address sender, bool approved) external;

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {ILBFactory} from './ILBFactory.sol';
import {ILBFlashLoanCallback} from './ILBFlashLoanCallback.sol';
import {ILBToken} from './ILBToken.sol';

interface ILBPair is ILBToken {
    error LBPair__ZeroBorrowAmount();
    error LBPair__AddressZero();
    error LBPair__AlreadyInitialized();
    error LBPair__EmptyMarketConfigs();
    error LBPair__FlashLoanCallbackFailed();
    error LBPair__FlashLoanInsufficientAmount();
    error LBPair__InsufficientAmountIn();
    error LBPair__InsufficientAmountOut();
    error LBPair__InvalidInput();
    error LBPair__InvalidStaticFeeParameters();
    error LBPair__OnlyFactory();
    error LBPair__OnlyProtocolFeeRecipient();
    error LBPair__OutOfLiquidity();
    error LBPair__TokenNotSupported();
    error LBPair__ZeroAmount(uint24 id);
    error LBPair__ZeroAmountsOut(uint24 id);
    error LBPair__ZeroShares(uint24 id);
    error LBPair__MaxTotalFeeExceeded();

    struct MintArrays {
        uint[] ids;
        bytes32[] amounts;
        uint[] liquidityMinted;
    }

    event DepositedToBins(address indexed sender, address indexed to, uint[] ids, bytes32[] amounts);

    event WithdrawnFromBins(address indexed sender, address indexed to, uint[] ids, bytes32[] amounts);

    event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees);

    event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees);

    event Swap(
        address indexed sender,
        address indexed to,
        uint24 id,
        bytes32 amountsIn,
        bytes32 amountsOut,
        uint24 volatilityAccumulator,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event StaticFeeParametersSet(
        address indexed sender,
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    );

    event FlashLoan(
        address indexed sender,
        ILBFlashLoanCallback indexed receiver,
        uint24 activeId,
        bytes32 amounts,
        bytes32 totalFees,
        bytes32 protocolFees
    );

    event OracleLengthIncreased(address indexed sender, uint16 oracleLength);

    event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference);

    function initialize(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator,
        uint24 activeId
    ) external;

    function getFactory() external view returns (ILBFactory factory);

    function getTokenX() external view returns (IERC20 tokenX);

    function getTokenY() external view returns (IERC20 tokenY);

    function getBinStep() external view returns (uint16 binStep);

    function getReserves() external view returns (uint128 reserveX, uint128 reserveY);

    function getActiveId() external view returns (uint24 activeId);

    function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY);

    function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId);

    function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY);

    function getStaticFeeParameters()
        external
        view
        returns (
            uint16 baseFactor,
            uint16 filterPeriod,
            uint16 decayPeriod,
            uint16 reductionFactor,
            uint24 variableFeeControl,
            uint16 protocolShare,
            uint24 maxVolatilityAccumulator
        );

    function getVariableFeeParameters()
        external
        view
        returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate);

    function getOracleParameters()
        external
        view
        returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp);

    function getOracleSampleAt(uint40 lookupTimestamp)
        external
        view
        returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed);

    function getPriceFromId(uint24 id) external view returns (uint price);

    function getIdFromPrice(uint price) external view returns (uint24 id);

    function getSwapIn(uint128 amountOut, bool swapForY)
        external
        view
        returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);

    function getSwapOut(uint128 amountIn, bool swapForY)
        external
        view
        returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);

    function swap(bool swapForY, address to) external returns (bytes32 amountsOut);

    function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external;

    function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo)
        external
        returns (bytes32 amountsReceived, bytes32 amountsLeft, uint[] memory liquidityMinted);

    function burn(address from, address to, uint[] calldata ids, uint[] calldata amountsToBurn)
        external
        returns (bytes32[] memory amounts);

    function collectProtocolFees() external returns (bytes32 collectedProtocolFees);

    function increaseOracleLength(uint16 newLength) external;

    function setStaticFeeParameters(
        uint16 baseFactor,
        uint16 filterPeriod,
        uint16 decayPeriod,
        uint16 reductionFactor,
        uint24 variableFeeControl,
        uint16 protocolShare,
        uint24 maxVolatilityAccumulator
    ) external;

    function forceDecay() external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import {IERC20} from '@openzeppelin-contracts/token/ERC20/IERC20.sol';

import {IJoeFactory} from './IJoeFactory.sol';
import {ILBFactory} from './ILBFactory.sol';
import {ILBLegacyFactory} from './ILBLegacyFactory.sol';
import {ILBLegacyRouter} from './ILBLegacyRouter.sol';
import {ILBPair} from './ILBPair.sol';
import {ILBToken} from './ILBToken.sol';
import {IWNative} from '../IWNATIVE.sol';

/**
 * @title Liquidity Book Router Interface
 * @author Trader Joe
 * @notice Required interface of LBRouter contract
 */
interface ILBRouter {
    error LBRouter__SenderIsNotWNATIVE();
    error LBRouter__PairNotCreated(address tokenX, address tokenY, uint binStep);
    error LBRouter__WrongAmounts(uint amount, uint reserve);
    error LBRouter__SwapOverflows(uint id);
    error LBRouter__BrokenSwapSafetyCheck();
    error LBRouter__NotFactoryOwner();
    error LBRouter__TooMuchTokensIn(uint excess);
    error LBRouter__BinReserveOverflows(uint id);
    error LBRouter__IdOverflows(int id);
    error LBRouter__LengthsMismatch();
    error LBRouter__WrongTokenOrder();
    error LBRouter__IdSlippageCaught(uint activeIdDesired, uint idSlippage, uint activeId);
    error LBRouter__AmountSlippageCaught(uint amountXMin, uint amountX, uint amountYMin, uint amountY);
    error LBRouter__IdDesiredOverflows(uint idDesired, uint idSlippage);
    error LBRouter__FailedToSendNATIVE(address recipient, uint amount);
    error LBRouter__DeadlineExceeded(uint deadline, uint currentTimestamp);
    error LBRouter__AmountSlippageBPTooBig(uint amountSlippage);
    error LBRouter__InsufficientAmountOut(uint amountOutMin, uint amountOut);
    error LBRouter__MaxAmountInExceeded(uint amountInMax, uint amountIn);
    error LBRouter__InvalidTokenPath(address wrongToken);
    error LBRouter__InvalidVersion(uint version);
    error LBRouter__WrongNativeLiquidityParameters(
        address tokenX, address tokenY, uint amountX, uint amountY, uint msgValue
    );

    /**
     * @dev This enum represents the version of the pair requested
     * - V1: Joe V1 pair
     * - V2: LB pair V2. Also called legacyPair
     * - V2_1: LB pair V2.1 (current version)
     */
    enum Version {
        V1,
        V2,
        V2_1
    }

    /**
     * @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) = 1e18 (100%) or 0 (0%)
     * - distributionY: The distribution of tokenY with sum(distributionY) = 1e18 (100%) or 0 (0%)
     * - to: The address of the recipient
     * - refundTo: The address of the recipient of the refunded tokens if too much tokens are sent
     * - deadline: The deadline of the transaction
     */
    struct LiquidityParameters {
        IERC20 tokenX;
        IERC20 tokenY;
        uint binStep;
        uint amountX;
        uint amountY;
        uint amountXMin;
        uint amountYMin;
        uint activeIdDesired;
        uint idSlippage;
        int[] deltaIds;
        uint[] distributionX;
        uint[] distributionY;
        address to;
        address refundTo;
        uint deadline;
    }

    /**
     * @dev The path parameters, such as:
     * - pairBinSteps: The list of bin steps of the pairs to go through
     * - versions: The list of versions of the pairs to go through
     * - tokenPath: The list of tokens in the path to go through
     */
    struct Path {
        uint[] pairBinSteps;
        Version[] versions;
        IERC20[] tokenPath;
    }

    function getFactory() external view returns (ILBFactory);

    function getLegacyFactory() external view returns (ILBLegacyFactory);

    function getV1Factory() external view returns (IJoeFactory);

    function getLegacyRouter() external view returns (ILBLegacyRouter);

    function getWNATIVE() external view returns (IWNative);

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

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

    function getSwapIn(ILBPair LBPair, uint128 amountOut, bool swapForY)
        external
        view
        returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);

    function getSwapOut(ILBPair LBPair, uint128 amountIn, bool swapForY)
        external
        view
        returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);

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

    function addLiquidity(LiquidityParameters calldata liquidityParameters)
        external
        returns (
            uint amountXAdded,
            uint amountYAdded,
            uint amountXLeft,
            uint amountYLeft,
            uint[] memory depositIds,
            uint[] memory liquidityMinted
        );

    function addLiquidityNATIVE(LiquidityParameters calldata liquidityParameters)
        external
        payable
        returns (
            uint amountXAdded,
            uint amountYAdded,
            uint amountXLeft,
            uint amountYLeft,
            uint[] memory depositIds,
            uint[] memory liquidityMinted
        );

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

    function removeLiquidityNATIVE(
        IERC20 token,
        uint16 binStep,
        uint amountTokenMin,
        uint amountNATIVEMin,
        uint[] memory ids,
        uint[] memory amounts,
        address payable to,
        uint deadline
    ) external returns (uint amountToken, uint amountNATIVE);

    function swapExactTokensForTokens(uint amountIn, uint amountOutMin, Path memory path, address to, uint deadline)
        external
        returns (uint amountOut);

    function swapExactTokensForNATIVE(
        uint amountIn,
        uint amountOutMinNATIVE,
        Path memory path,
        address payable to,
        uint deadline
    ) external returns (uint amountOut);

    function swapExactNATIVEForTokens(uint amountOutMin, Path memory path, address to, uint deadline)
        external
        payable
        returns (uint amountOut);

    function swapTokensForExactTokens(uint amountOut, uint amountInMax, Path memory path, address to, uint deadline)
        external
        returns (uint[] memory amountsIn);

    function swapTokensForExactNATIVE(
        uint amountOut,
        uint amountInMax,
        Path memory path,
        address payable to,
        uint deadline
    ) external returns (uint[] memory amountsIn);

    function swapNATIVEForExactTokens(uint amountOut, Path memory path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amountsIn);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        Path memory path,
        address to,
        uint deadline
    ) external returns (uint amountOut);

    function swapExactTokensForNATIVESupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMinNATIVE,
        Path memory path,
        address payable to,
        uint deadline
    ) external returns (uint amountOut);

    function swapExactNATIVEForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        Path memory path,
        address to,
        uint deadline
    ) external payable returns (uint amountOut);

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

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

/**
 * @title Liquidity Book Token Interface
 * @author Trader Joe
 * @notice Interface to interact with the LBToken.
 */
interface ILBToken {
    error LBToken__AddressThisOrZero();
    error LBToken__InvalidLength();
    error LBToken__SelfApproval(address owner);
    error LBToken__SpenderNotApproved(address from, address spender);
    error LBToken__TransferExceedsBalance(address from, uint id, uint amount);
    error LBToken__BurnExceedsBalance(address from, uint id, uint amount);

    event TransferBatch(address indexed sender, address indexed from, address indexed to, uint[] ids, uint[] 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 totalSupply(uint id) external view returns (uint);

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

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

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

    function approveForAll(address spender, bool approved) external;

    function batchTransferFrom(address from, address to, uint[] calldata ids, uint[] calldata amounts) external;
}

// 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 {
    error PendingOwnable__AddressZero();
    error PendingOwnable__NoPendingOwner();
    error PendingOwnable__NotOwner();
    error PendingOwnable__NotPendingOwner();
    error PendingOwnable__PendingOwnerAlreadySet();

    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;
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

import {SwapInfo} from '../../hook/IMarginTradingHook.sol';

interface IBaseSwapHelper {
    function swap(SwapInfo calldata _swapInfo) external;
}

// SPDX-License-Identifier: None
pragma solidity ^0.8.19;

// @ mnt-eth = 3200, eth-usd = 2200
//    pair         |  col | bor |  B  |  Q  |   limit (sl)  |  limit (tp)  |
// ETH-USD (long)  |  ETH | USD | ETH | USD |    < 2000     |    > 3000    |
// ETH-USD (short) |  USD | ETH | ETH | USD |    > 3000     |    < 2000    |
// MNT-ETH (long)  |  MNT | ETH | ETH | MNT |    < 3000     |    > 4000    |
// MNT-ETH (short) |  ETH | MNT | ETH | MNT |    > 4000     |    > 3000    |

// enums
enum OrderType {
    StopLoss,
    TakeProfit
}

enum OrderStatus {
    Cancelled,
    Active,
    Filled
}

enum SwapType {
    OpenExactIn,
    CloseExactIn,
    CloseExactOut
}

// structs
struct Order {
    uint initPosId; // nft id
    uint triggerPrice_e36; // price (base asset price / quote asset price) to trigger limit order
    uint limitPrice_e36; // price limit price (base asset price / quote asset price) to fill order
    uint collAmt; // size of collateral to be used in order
    address tokenOut; // token to transfer to pos owner
    OrderType orderType; // stop loss or take profit
    OrderStatus status; // cancelled, active, filled
    address recipient; // address to receive tokenOut
}

struct MarginPos {
    address collPool; // lending pool to deposit holdToken
    address borrPool; // lending pool to borrow borrowToken
    address baseAsset; // base asset of position
    address quoteAsset; // quote asset of position
    bool isLongBaseAsset; // long base asset or not
}

struct SwapInfo {
    uint initPosId; // nft id
    SwapType swapType; // swap type
    address tokenIn; // token to swap
    address tokenOut; // token to receive from swap
    uint amtOut; // token amount out info for the swap
    bytes data; // swap data
}

/// @notice user has to be able to receive native tokens
interface IMarginTradingHook {
    // events
    event SwapToIncreasePos(
        uint indexed initPosId, address indexed tokenIn, address indexed tokenOut, uint amtIn, uint amtOut
    );
    event SwapToReducePos(
        uint indexed initPosId, address indexed tokenIn, address indexed tokenOut, uint amtIn, uint amtOut
    );

    event IncreasePos(
        uint indexed initPosId, address indexed tokenIn, address indexed borrToken, uint amtIn, uint borrowAmt
    );
    event ReducePos(uint indexed initPosId, address indexed tokenOut, uint amtOut, uint size, uint repayAmt);
    event CreateOrder(
        uint indexed initPosId,
        uint indexed orderId,
        address tokenOut,
        uint triggerPrice_e36,
        uint limitPrice_e36,
        uint size,
        OrderType orderType
    );
    event CancelOrder(uint indexed initPosId, uint indexed orderId);
    event FillOrder(uint indexed initPosId, uint indexed orderId, address tokenOut, uint amtOut);
    event SetSwapHelper(address swapHelper);
    event SetQuoteAsset(address tokenA, address tokenB, address quoteAsset);

    // struct
    struct IncreasePosInternalParam {
        uint initPosId; // nft id
        address tokenIn; // token to transfer from msg.sender
        uint amtIn; // token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
        address borrPool; // lending pool to borrow
        uint borrAmt; // token amount to borrow
        address collPool; // lending pool to deposit
        bytes data; // swap data
        uint minAmtOut; // minimum token amount to receive from swap
    }

    struct ReducePosInternalParam {
        uint initPosId; // nft id
        uint collAmt; // collateral amt to reduce
        uint repayShares; // debt shares to repay
        address tokenOut; // token to transfer to msg sender
        uint minAmtOut; // minimum amount of token to transfer to msg sender
        bool returnNative; // return wNative as native token or not (using balanceOf(address(this)))
        bytes data; // swap data
    }

    // functions
    /// @dev open margin trading position
    /// @param _mode position mode to be used
    /// @param _viewer address to view position
    /// @param  _tokenIn token to transfer from msg.sender
    /// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
    /// @param _borrPool lending pool to borrow
    /// @param _borrAmt token amount to borrow
    /// @param _collPool lending pool to deposit
    /// @param _data swap data
    /// @param _minAmtOut minimum tokenOut to receive from swap
    /// @return posId margin trading position id
    ///         initPosId init position id (nft id)
    ///         amtOut amount of received token from swap
    function openPos(
        uint16 _mode,
        address _viewer,
        address _tokenIn,
        uint _amtIn,
        address _borrPool,
        uint _borrAmt,
        address _collPool,
        bytes calldata _data,
        uint _minAmtOut
    ) external payable returns (uint posId, uint initPosId, uint amtOut);

    /// @dev increase position size (need to borrow)
    /// @param _posId margin trading position id
    /// @param  _tokenIn token to transfer from msg.sender
    /// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
    /// @param _borrAmt token amount to borrow
    /// @param _data swap data
    /// @param _minAmtOut minimum tokenOut to receive from swap
    /// @return amtOut amount of received token from swap
    function increasePos(
        uint _posId,
        address _tokenIn,
        uint _amtIn,
        uint _borrAmt,
        bytes calldata _data,
        uint _minAmtOut
    ) external payable returns (uint amtOut);

    /// @dev add collarteral to position
    /// @param _posId position id
    /// @param _amtIn token amount to transfer from msg sender (for wNative, amt to transfer will reduce by msg value)
    function addCollateral(uint _posId, uint _amtIn) external payable;

    /// @dev remove collateral from position
    /// @param _posId margin trading position id
    /// @param _shares shares amount to withdraw
    /// @param _returnNative return wNative as native token or not (using balanceOf(address(this)))
    function removeCollateral(uint _posId, uint _shares, bool _returnNative) external;

    /// @dev repay debt of position
    /// @param _posId margin trading position id
    /// @param _repayShares debt shares to repay
    /// @return repayAmt actual amount of debt repaid
    function repayDebt(uint _posId, uint _repayShares) external payable returns (uint repayAmt);

    /// @dev reduce position size
    /// @param _posId margin trading position id
    /// @param _collAmt collateral amt to reduce
    /// @param _repayShares debt shares to repay
    /// @param _tokenOut token to transfer to msg sender
    /// @param _minAmtOut minimum amount of token to transfer to msg sender
    /// @param _returnNative return wNative as native token or not (using balanceOf(address(this)))
    /// @param _data swap data
    /// @return amtOut actual amount of token transferred to msg sender
    function reducePos(
        uint _posId,
        uint _collAmt,
        uint _repayShares,
        address _tokenOut,
        uint _minAmtOut,
        bool _returnNative,
        bytes calldata _data
    ) external returns (uint amtOut);

    /// @dev create stop loss order
    /// @param _posId margin trading position id
    /// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
    /// @param _tokenOut token to transfer to msg sender
    /// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
    /// @param _collAmt collateral size for the order
    /// @return orderId order id
    function addStopLossOrder(
        uint _posId,
        uint _triggerPrice_e36,
        address _tokenOut,
        uint _limitPrice_e36,
        uint _collAmt
    ) external returns (uint orderId);

    /// @dev create take profit order
    /// @param _posId margin trading position id
    /// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
    /// @param _tokenOut token to transfer to msg sender
    /// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
    /// @param _collAmt share of collateral to use in order
    /// @return orderId order id
    function addTakeProfitOrder(
        uint _posId,
        uint _triggerPrice_e36,
        address _tokenOut,
        uint _limitPrice_e36,
        uint _collAmt
    ) external returns (uint orderId);

    /// @dev cancel and create new order
    /// @param _orderId order id
    /// @param _triggerPrice_e36 oracle price (quote asset price / base asset price) to trigger limit order
    /// @param _tokenOut token to transfer to msg sender
    /// @param _limitPrice_e36 price limit price (quote asset price / base asset price) to fill order
    /// @param _collAmt share of collateral to use in order
    /// @return newOrderId new order id
    function cancelAndCreateNewOrder(
        uint _posId,
        uint _orderId,
        uint _triggerPrice_e36,
        address _tokenOut,
        uint _limitPrice_e36,
        uint _collAmt
    ) external returns (uint newOrderId);

    /// @dev cancel order
    /// @param _posId margin trading position id
    /// @param _orderId order id
    function cancelOrder(uint _posId, uint _orderId) external;

    /// @dev arbitrager reduce position in order and collateral at limit price
    /// @param _orderId order id
    function fillOrder(uint _orderId) external;

    /// @notice _tokenA and _tokenB MUST be different
    /// @dev set quote asset of pair
    /// @param _tokenA token A of pair
    /// @param _tokenB token B of pair
    /// @param _quoteAsset quote asset of pair
    function setQuoteAsset(address _tokenA, address _tokenB, address _quoteAsset) external;

    /// @dev set swap helper
    /// @param _swapHelper swap helper address
    function setSwapHelper(address _swapHelper) external;

    /// @dev get base asset and token asset of pair
    /// @param _tokenA token A of pair
    /// @param _tokenB token B of pair
    /// @return baseAsset base asset of pair
    /// @return quoteAsset quote asset of pair
    function getBaseAssetAndQuoteAsset(address _tokenA, address _tokenB)
        external
        view
        returns (address baseAsset, address quoteAsset);

    /// @dev get order information
    /// @param _orderId order id
    /// @return order order information
    function getOrder(uint _orderId) external view returns (Order memory);

    /// @dev get margin position information
    /// @param _initPosId init position id (nft id)
    /// @return marginPos margin position information
    function getMarginPos(uint _initPosId) external view returns (MarginPos memory);

    /// @dev get position's orders length
    /// @param _initPosId init position id (nft id)
    function getPosOrdersLength(uint _initPosId) external view returns (uint);

    /// @dev get hook's order id
    function lastOrderId() external view returns (uint);

    /// @dev get all position's order ids
    /// @param _initPosId init position id (nft id)
    function getPosOrderIds(uint _initPosId) external view returns (uint[] memory);
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "appendCBOR": true,
    "bytecodeHash": "ipfs",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "@forge-std/=lib/forge-std/src/",
    "@openzeppelin-contracts/=contracts/.cache/OpenZeppelin/v4.9.3/",
    "@openzeppelin-contracts-upgradeable/=contracts/.cache/OpenZeppelin-Upgradeable/v4.9.3/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"
  ],
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"AGNI_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUSIONX_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MOE_LB_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MOE_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"initPosId","type":"uint256"},{"internalType":"enum SwapType","name":"swapType","type":"uint8"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amtOut","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct SwapInfo","name":"_swapInfo","type":"tuple"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50611730806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806387d2af1f1461005c578063a2f9e11c14610093578063b00c343f146100ae578063bdbb073a146100c9578063c2f8bbf3146100e4575b600080fd5b61007773eaee7ee68874218c3558b40063c42b82d3e7232a81565b6040516001600160a01b03909116815260200160405180910390f35b61007773afb85a12babfafabfe1a518594492d5a830e782a81565b61007773319b69888b0d11cec22caa5034e25fffbdc8842181565b610077735989fb161568b9f133edf5cf6787f5597762797f81565b6100f76100f2366004610e96565b6100f9565b005b60008061010960a0840184610ed8565b8101906101169190610fd6565b909250905073eaee7ee68874218c3558b40063c42b82d3e72329196001600160a01b0383160161014f5761014a8382610236565b610219565b73319b69888b0d11cec22caa5034e25fffbdc88420196001600160a01b0383160161017e5761014a8382610449565b735989fb161568b9f133edf5cf6787f5597762797e196001600160a01b038316016101ad5761014a838261067c565b73afb85a12babfafabfe1a518594492d5a830e7829196001600160a01b038316016101dc5761014a8382610829565b60405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b60448201526064015b60405180910390fd5b61023161022c6060850160408601611069565b61099f565b505050565b6000808280602001905181019061024d91906110aa565b909250905060006102646060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156102aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ce919061114c565b90506102fe6102e36060870160408801611069565b73eaee7ee68874218c3558b40063c42b82d3e7232a83610a2a565b60026103106040870160208801611188565b600281111561032157610321611165565b036103b657604051634401edf760e11b815273eaee7ee68874218c3558b40063c42b82d3e7232a90638803dbee906103699060808901359085908890339089906004016111a5565b6000604051808303816000875af1158015610388573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103b0919081019061127c565b50610442565b6040516338ed173960e01b815273eaee7ee68874218c3558b40063c42b82d3e7232a906338ed1739906103f990849060808a0135908890339089906004016111a5565b6000604051808303816000875af1158015610418573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610440919081019061127c565b505b5050505050565b6000808280602001905181019061046091906112d5565b909250905060006104776060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156104bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e1919061114c565b90506105116104f66060870160408801611069565b73319b69888b0d11cec22caa5034e25fffbdc8842183610a2a565b60026105236040870160208801611188565b600281111561053457610534611165565b036105da576040805160a081018252848152336020820152808201849052608080880135606083015281018390529051631e51809360e31b815273319b69888b0d11cec22caa5034e25fffbdc884219163f28c04989161059791906004016113d3565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b0919061114c565b6040805160a0810182528481523360208201528082018490526060810183905260808781013590820152905163c04b8d5960e01b815273319b69888b0d11cec22caa5034e25fffbdc884219163c04b8d599161063991906004016113d3565b6020604051808303816000875af1158015610658573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610440919061114c565b6000808280602001905181019061069391906112d5565b909250905060006106aa6060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156106f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610714919061114c565b90506107446107296060870160408801611069565b735989fb161568b9f133edf5cf6787f5597762797f83610a2a565b60026107566040870160208801611188565b600281111561076757610767611165565b036107ca576040805160a081018252848152336020820152808201849052608080880135606083015281018390529051631e51809360e31b8152735989fb161568b9f133edf5cf6787f5597762797f9163f28c04989161059791906004016113d3565b6040805160a0810182528481523360208201528082018490526060810183905260808781013590820152905163c04b8d5960e01b8152735989fb161568b9f133edf5cf6787f5597762797f9163c04b8d599161063991906004016113d3565b60008082806020019051810190610840919061144a565b909250905060006108576060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561089d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c1919061114c565b90506108f16108d66060870160408801611069565b73afb85a12babfafabfe1a518594492d5a830e782a83610a2a565b60026109036040870160208801611188565b600281111561091457610914611165565b0361095c5760405163092fe8e760e41b815273afb85a12babfafabfe1a518594492d5a830e782a906392fe8e70906103699060808901359085908890339089906004016115a6565b6040516315221fd760e11b815273afb85a12babfafabfe1a518594492d5a830e782a90632a443fae9061063990849060808a0135908890339089906004016115a6565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156109e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0a919061114c565b90508015610a2657610a266001600160a01b0383163383610ab9565b5050565b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d919061114c565b1015610231576102316001600160a01b03841683600019610b1c565b6040516001600160a01b03831660248201526044810182905261023190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610c31565b801580610b965750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b94919061114c565b155b610c015760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610210565b6040516001600160a01b03831660248201526044810182905261023190849063095ea7b360e01b90606401610ae5565b6000610c86826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610d069092919063ffffffff16565b9050805160001480610ca7575080806020019051810190610ca791906116a9565b6102315760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610210565b6060610d158484600085610d1d565b949350505050565b606082471015610d7e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610210565b600080866001600160a01b03168587604051610d9a91906116cb565b60006040518083038185875af1925050503d8060008114610dd7576040519150601f19603f3d011682016040523d82523d6000602084013e610ddc565b606091505b5091509150610ded87838387610df8565b979650505050505050565b60608315610e67578251600003610e60576001600160a01b0385163b610e605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610210565b5081610d15565b610d158383815115610e7c5781518083602001fd5b8060405162461bcd60e51b815260040161021091906116e7565b600060208284031215610ea857600080fd5b813567ffffffffffffffff811115610ebf57600080fd5b820160c08185031215610ed157600080fd5b9392505050565b6000808335601e19843603018112610eef57600080fd5b83018035915067ffffffffffffffff821115610f0a57600080fd5b602001915036819003821315610f1f57600080fd5b9250929050565b6001600160a01b0381168114610f3b57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610f7757610f77610f3e565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610fa657610fa6610f3e565b604052919050565b600067ffffffffffffffff821115610fc857610fc8610f3e565b50601f01601f191660200190565b60008060408385031215610fe957600080fd5b8235610ff481610f26565b9150602083013567ffffffffffffffff81111561101057600080fd5b8301601f8101851361102157600080fd5b803561103461102f82610fae565b610f7d565b81815286602083850101111561104957600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561107b57600080fd5b8135610ed181610f26565b600067ffffffffffffffff8211156110a0576110a0610f3e565b5060051b60200190565b600080604083850312156110bd57600080fd5b825167ffffffffffffffff8111156110d457600080fd5b8301601f810185136110e557600080fd5b805160206110f561102f83611086565b82815260059290921b8301810191818101908884111561111457600080fd5b938201935b8385101561113b57845161112c81610f26565b82529382019390820190611119565b969091015195979596505050505050565b60006020828403121561115e57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b60038110610f3b57600080fd5b60006020828403121561119a57600080fd5b8135610ed18161117b565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156111f55784516001600160a01b0316835293830193918301916001016111d0565b50506001600160a01b03969096166060850152505050608001529392505050565b600082601f83011261122757600080fd5b8151602061123761102f83611086565b82815260059290921b8401810191818101908684111561125657600080fd5b8286015b84811015611271578051835291830191830161125a565b509695505050505050565b60006020828403121561128e57600080fd5b815167ffffffffffffffff8111156112a557600080fd5b610d1584828501611216565b60005b838110156112cc5781810151838201526020016112b4565b50506000910152565b600080604083850312156112e857600080fd5b825167ffffffffffffffff8111156112ff57600080fd5b8301601f8101851361131057600080fd5b805161131e61102f82610fae565b81815286602083850101111561133357600080fd5b6113448260208301602086016112b1565b60209590950151949694955050505050565b6000815180845261136e8160208601602086016112b1565b601f01601f19169290920160200192915050565b6000815160a0845261139760a0850182611356565b6020848101516001600160a01b031690860152604080850151908601526060808501519086015260809384015193909401929092525090919050565b602081526000610ed16020830184611382565b600082601f8301126113f757600080fd5b8151602061140761102f83611086565b82815260059290921b8401810191818101908684111561142657600080fd5b8286015b8481101561127157805161143d81610f26565b835291830191830161142a565b6000806040838503121561145d57600080fd5b825167ffffffffffffffff8082111561147557600080fd5b908401906060828703121561148957600080fd5b611491610f54565b8251828111156114a057600080fd5b6114ac88828601611216565b825250602080840151838111156114c257600080fd5b8401601f810189136114d357600080fd5b80516114e161102f82611086565b81815260059190911b8201830190838101908b83111561150057600080fd5b928401925b828410156115275783516115188161117b565b82529284019290840190611505565b8585015250505060408401518381111561154057600080fd5b61154c898287016113e6565b6040840152509590950151949694955050505050565b600081518084526020808501945080840160005b8381101561159b5781516001600160a01b031687529582019590820190600101611576565b509495945050505050565b85815260006020868184015260a0604084015261010083018651606060a0860152818151808452610120870191508483019350600092505b808310156115fe57835182529284019260019290920191908401906115de565b5083890151609f19878303810160c08901528151808452918601945092506000918501905b808310156116615784516003811061164b57634e487b7160e01b600052602160045260246000fd5b8252938501936001929092019190850190611623565b5060408a01519450828782030160e088015261167d8186611562565b9550505050505061169960608301856001600160a01b03169052565b8260808301529695505050505050565b6000602082840312156116bb57600080fd5b81518015158114610ed157600080fd5b600082516116dd8184602087016112b1565b9190910192915050565b602081526000610ed1602083018461135656fea2646970667358221220e2e9b63e16f9628947213f23697874317a42c687c873be6759d8e0c74ec3511064736f6c63430008130033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100575760003560e01c806387d2af1f1461005c578063a2f9e11c14610093578063b00c343f146100ae578063bdbb073a146100c9578063c2f8bbf3146100e4575b600080fd5b61007773eaee7ee68874218c3558b40063c42b82d3e7232a81565b6040516001600160a01b03909116815260200160405180910390f35b61007773afb85a12babfafabfe1a518594492d5a830e782a81565b61007773319b69888b0d11cec22caa5034e25fffbdc8842181565b610077735989fb161568b9f133edf5cf6787f5597762797f81565b6100f76100f2366004610e96565b6100f9565b005b60008061010960a0840184610ed8565b8101906101169190610fd6565b909250905073eaee7ee68874218c3558b40063c42b82d3e72329196001600160a01b0383160161014f5761014a8382610236565b610219565b73319b69888b0d11cec22caa5034e25fffbdc88420196001600160a01b0383160161017e5761014a8382610449565b735989fb161568b9f133edf5cf6787f5597762797e196001600160a01b038316016101ad5761014a838261067c565b73afb85a12babfafabfe1a518594492d5a830e7829196001600160a01b038316016101dc5761014a8382610829565b60405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b60448201526064015b60405180910390fd5b61023161022c6060850160408601611069565b61099f565b505050565b6000808280602001905181019061024d91906110aa565b909250905060006102646060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156102aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ce919061114c565b90506102fe6102e36060870160408801611069565b73eaee7ee68874218c3558b40063c42b82d3e7232a83610a2a565b60026103106040870160208801611188565b600281111561032157610321611165565b036103b657604051634401edf760e11b815273eaee7ee68874218c3558b40063c42b82d3e7232a90638803dbee906103699060808901359085908890339089906004016111a5565b6000604051808303816000875af1158015610388573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103b0919081019061127c565b50610442565b6040516338ed173960e01b815273eaee7ee68874218c3558b40063c42b82d3e7232a906338ed1739906103f990849060808a0135908890339089906004016111a5565b6000604051808303816000875af1158015610418573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610440919081019061127c565b505b5050505050565b6000808280602001905181019061046091906112d5565b909250905060006104776060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156104bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e1919061114c565b90506105116104f66060870160408801611069565b73319b69888b0d11cec22caa5034e25fffbdc8842183610a2a565b60026105236040870160208801611188565b600281111561053457610534611165565b036105da576040805160a081018252848152336020820152808201849052608080880135606083015281018390529051631e51809360e31b815273319b69888b0d11cec22caa5034e25fffbdc884219163f28c04989161059791906004016113d3565b6020604051808303816000875af11580156105b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b0919061114c565b6040805160a0810182528481523360208201528082018490526060810183905260808781013590820152905163c04b8d5960e01b815273319b69888b0d11cec22caa5034e25fffbdc884219163c04b8d599161063991906004016113d3565b6020604051808303816000875af1158015610658573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610440919061114c565b6000808280602001905181019061069391906112d5565b909250905060006106aa6060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156106f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610714919061114c565b90506107446107296060870160408801611069565b735989fb161568b9f133edf5cf6787f5597762797f83610a2a565b60026107566040870160208801611188565b600281111561076757610767611165565b036107ca576040805160a081018252848152336020820152808201849052608080880135606083015281018390529051631e51809360e31b8152735989fb161568b9f133edf5cf6787f5597762797f9163f28c04989161059791906004016113d3565b6040805160a0810182528481523360208201528082018490526060810183905260808781013590820152905163c04b8d5960e01b8152735989fb161568b9f133edf5cf6787f5597762797f9163c04b8d599161063991906004016113d3565b60008082806020019051810190610840919061144a565b909250905060006108576060860160408701611069565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561089d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c1919061114c565b90506108f16108d66060870160408801611069565b73afb85a12babfafabfe1a518594492d5a830e782a83610a2a565b60026109036040870160208801611188565b600281111561091457610914611165565b0361095c5760405163092fe8e760e41b815273afb85a12babfafabfe1a518594492d5a830e782a906392fe8e70906103699060808901359085908890339089906004016115a6565b6040516315221fd760e11b815273afb85a12babfafabfe1a518594492d5a830e782a90632a443fae9061063990849060808a0135908890339089906004016115a6565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156109e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0a919061114c565b90508015610a2657610a266001600160a01b0383163383610ab9565b5050565b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d919061114c565b1015610231576102316001600160a01b03841683600019610b1c565b6040516001600160a01b03831660248201526044810182905261023190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610c31565b801580610b965750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610b70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b94919061114c565b155b610c015760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610210565b6040516001600160a01b03831660248201526044810182905261023190849063095ea7b360e01b90606401610ae5565b6000610c86826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610d069092919063ffffffff16565b9050805160001480610ca7575080806020019051810190610ca791906116a9565b6102315760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610210565b6060610d158484600085610d1d565b949350505050565b606082471015610d7e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610210565b600080866001600160a01b03168587604051610d9a91906116cb565b60006040518083038185875af1925050503d8060008114610dd7576040519150601f19603f3d011682016040523d82523d6000602084013e610ddc565b606091505b5091509150610ded87838387610df8565b979650505050505050565b60608315610e67578251600003610e60576001600160a01b0385163b610e605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610210565b5081610d15565b610d158383815115610e7c5781518083602001fd5b8060405162461bcd60e51b815260040161021091906116e7565b600060208284031215610ea857600080fd5b813567ffffffffffffffff811115610ebf57600080fd5b820160c08185031215610ed157600080fd5b9392505050565b6000808335601e19843603018112610eef57600080fd5b83018035915067ffffffffffffffff821115610f0a57600080fd5b602001915036819003821315610f1f57600080fd5b9250929050565b6001600160a01b0381168114610f3b57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610f7757610f77610f3e565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610fa657610fa6610f3e565b604052919050565b600067ffffffffffffffff821115610fc857610fc8610f3e565b50601f01601f191660200190565b60008060408385031215610fe957600080fd5b8235610ff481610f26565b9150602083013567ffffffffffffffff81111561101057600080fd5b8301601f8101851361102157600080fd5b803561103461102f82610fae565b610f7d565b81815286602083850101111561104957600080fd5b816020840160208301376000602083830101528093505050509250929050565b60006020828403121561107b57600080fd5b8135610ed181610f26565b600067ffffffffffffffff8211156110a0576110a0610f3e565b5060051b60200190565b600080604083850312156110bd57600080fd5b825167ffffffffffffffff8111156110d457600080fd5b8301601f810185136110e557600080fd5b805160206110f561102f83611086565b82815260059290921b8301810191818101908884111561111457600080fd5b938201935b8385101561113b57845161112c81610f26565b82529382019390820190611119565b969091015195979596505050505050565b60006020828403121561115e57600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b60038110610f3b57600080fd5b60006020828403121561119a57600080fd5b8135610ed18161117b565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b818110156111f55784516001600160a01b0316835293830193918301916001016111d0565b50506001600160a01b03969096166060850152505050608001529392505050565b600082601f83011261122757600080fd5b8151602061123761102f83611086565b82815260059290921b8401810191818101908684111561125657600080fd5b8286015b84811015611271578051835291830191830161125a565b509695505050505050565b60006020828403121561128e57600080fd5b815167ffffffffffffffff8111156112a557600080fd5b610d1584828501611216565b60005b838110156112cc5781810151838201526020016112b4565b50506000910152565b600080604083850312156112e857600080fd5b825167ffffffffffffffff8111156112ff57600080fd5b8301601f8101851361131057600080fd5b805161131e61102f82610fae565b81815286602083850101111561133357600080fd5b6113448260208301602086016112b1565b60209590950151949694955050505050565b6000815180845261136e8160208601602086016112b1565b601f01601f19169290920160200192915050565b6000815160a0845261139760a0850182611356565b6020848101516001600160a01b031690860152604080850151908601526060808501519086015260809384015193909401929092525090919050565b602081526000610ed16020830184611382565b600082601f8301126113f757600080fd5b8151602061140761102f83611086565b82815260059290921b8401810191818101908684111561142657600080fd5b8286015b8481101561127157805161143d81610f26565b835291830191830161142a565b6000806040838503121561145d57600080fd5b825167ffffffffffffffff8082111561147557600080fd5b908401906060828703121561148957600080fd5b611491610f54565b8251828111156114a057600080fd5b6114ac88828601611216565b825250602080840151838111156114c257600080fd5b8401601f810189136114d357600080fd5b80516114e161102f82611086565b81815260059190911b8201830190838101908b83111561150057600080fd5b928401925b828410156115275783516115188161117b565b82529284019290840190611505565b8585015250505060408401518381111561154057600080fd5b61154c898287016113e6565b6040840152509590950151949694955050505050565b600081518084526020808501945080840160005b8381101561159b5781516001600160a01b031687529582019590820190600101611576565b509495945050505050565b85815260006020868184015260a0604084015261010083018651606060a0860152818151808452610120870191508483019350600092505b808310156115fe57835182529284019260019290920191908401906115de565b5083890151609f19878303810160c08901528151808452918601945092506000918501905b808310156116615784516003811061164b57634e487b7160e01b600052602160045260246000fd5b8252938501936001929092019190850190611623565b5060408a01519450828782030160e088015261167d8186611562565b9550505050505061169960608301856001600160a01b03169052565b8260808301529695505050505050565b6000602082840312156116bb57600080fd5b81518015158114610ed157600080fd5b600082516116dd8184602087016112b1565b9190910192915050565b602081526000610ed1602083018461135656fea2646970667358221220e2e9b63e16f9628947213f23697874317a42c687c873be6759d8e0c74ec3511064736f6c63430008130033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.