ETH Price: $3,609.63 (+4.74%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x7bC0DE19...0538383AD
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
CurveStableSwapApp

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 36 : CurveStableSwapApp.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

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

import { AppAccountBase } from "src/apps/base/AppAccountBase.sol";
import { AppBase } from "src/apps/base/AppBase.sol";
import { CurveAppError } from "src/apps/curve/CurveAppError.sol";

import { ICurveStableSwapApp } from "src/interfaces/curve/ICurveStableSwapApp.sol";
import { ICurveStableSwapAppBeacon } from "src/interfaces/curve/ICurveStableSwapAppBeacon.sol";
import { ICurveStableSwapNG } from "src/interfaces/curve/ICurveStableSwapNG.sol";
import { ICurveStableSwapFactoryNG } from "src/interfaces/curve/ICurveStableSwapFactoryNG.sol";

contract CurveStableSwapApp is AppAccountBase, ICurveStableSwapApp {
    using SafeERC20 for IERC20;

    constructor() {
        _disableInitializers();
    }

    /*///////////////////////////////////////////////////////////////
                    			MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Allows the authorized operations party to exchange tokens on the stable swap pool.
     * @param _stableSwapPool The address of the stable swap pool.
     * @param _fromToken The address of the ERC20 token provided to exchange.
     * @param _toToken The address of the ERC20 token to receive from the exchange.
     * @param _fromAmount The amount of tokens to exchange.
     * @param _minToAmount The minimum amount of tokens to receive.
     */
    function exchange(address _stableSwapPool, address _fromToken, address _toToken, uint256 _fromAmount, uint256 _minToAmount)
        external
        nonReentrant
        requiresAuthorizedOperationsParty
    {
        _validatePoolAddress(_stableSwapPool);
        // convert token addresses to pool indices, reverts if pool and tokens aren't valid
        (int128 fromTokenIndex, int128 toTokenIndex,) = ICurveStableSwapFactoryNG(_getAppBeacon().curveStableswapFactoryNG())
            .get_coin_indices(_stableSwapPool, _fromToken, _toToken);
        IERC20(_fromToken).approve(_stableSwapPool, _fromAmount);
        uint256 receivedAmount = ICurveStableSwapNG(_stableSwapPool).exchange(fromTokenIndex, toTokenIndex, _fromAmount, _minToAmount);
        emit TokensExchanged(_stableSwapPool, _fromToken, _toToken, _fromAmount, receivedAmount);
    }

    /**
     * @notice Adds liquidity to the specified pool
     * @dev The arrays indices have to match the indices of the tokens in the pool.
     * @param _stableSwapPool The address of the pool to add liquidity to.
     * @param _tokens An array of token addresses to add as liquidity.
     * @param _amounts An array of token amounts to add as liquidity.
     * @param _minLPAmount The minimum amount of LP tokens to receive.
     */
    function addLiquidity(address _stableSwapPool, address[] calldata _tokens, uint256[] calldata _amounts, uint256 _minLPAmount)
        external
        nonReentrant
        requiresAuthorizedOperationsParty
    {
        _validatePoolAddress(_stableSwapPool);
        address[] memory coins = ICurveStableSwapFactoryNG(_getAppBeacon().curveStableswapFactoryNG()).get_coins(_stableSwapPool);
        // check and approve the pool to add the tokens as liquidity
        for (uint256 i = 0; i < _tokens.length; i++) {
            if (coins[i] != _tokens[i]) revert CurveAppError.InvalidToken();
            IERC20(_tokens[i]).approve(_stableSwapPool, _amounts[i]);
        }

        // provide the liquidity
        uint256 lpAmount = ICurveStableSwapNG(_stableSwapPool).add_liquidity(_amounts, _minLPAmount);
        emit LiquidityAdded(_stableSwapPool, _amounts, lpAmount);
    }

    /**
     * @notice Removes liquidity for a single token from the Curve stable swap pool.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _tokenIndex The index of the token to remove liquidity.
     * @param _lpAmount The amount of LP tokens to burn.
     * @param _minReceiveAmount The minimum amount of tokens to receive in return.
     * @return The amount of tokens received after removing liquidity.
     */
    function removeSingleTokenLiquidity(address _stableSwapPool, int128 _tokenIndex, uint256 _lpAmount, uint256 _minReceiveAmount)
        external
        nonReentrant
        requiresAuthorizedOperationsParty
        returns (uint256)
    {
        return _removeSingleTokenLiquidity(_stableSwapPool, _tokenIndex, _lpAmount, _minReceiveAmount);
    }

    /**
     * @notice Withdraw coins from a Curve stable swap pool in an imbalanced amount.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _lpAmount The max amount of LP tokens to burn.
     * @param _amounts The amount of tokens to receive in return.
     */
    function removeLiquidityImbalance(address _stableSwapPool, uint256 _lpAmount, uint256[] calldata _amounts)
        external
        nonReentrant
        requiresAuthorizedOperationsParty
    {
        _removeLiquidityImbalance(_stableSwapPool, _lpAmount, _amounts);
    }

    /**
     * @notice Swaps ERC20 tokens to USDC at the current exchange amount and then recovers to mainAccount
     * @param _stableSwapPool The address of the stable swap pool.
     * @param _fromToken The address of the ERC20 token to recover.
     * @param _minToAmount The minimum amount of USDC to receive.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverERC20ToUSDC(address _stableSwapPool, address _fromToken, uint256 _minToAmount)
        external
        nonReentrant
        requiresAuthorizedRecoveryParty
    {
        _validatePoolAddress(_stableSwapPool);
        uint256 balance = IERC20(_fromToken).balanceOf(address(this));
        ICurveStableSwapAppBeacon appBeacon = _getAppBeacon();
        address USDC = appBeacon.USDC();
        // convert token addresses to pool indices, reverts if pool and tokens aren't valid
        (int128 fromTokenIndex, int128 toTokenIndex,) =
            ICurveStableSwapFactoryNG(_getAppBeacon().curveStableswapFactoryNG()).get_coin_indices(_stableSwapPool, _fromToken, USDC);
        IERC20(_fromToken).approve(_stableSwapPool, balance);
        // swap to USDC
        uint256 receivedAmount = ICurveStableSwapNG(_stableSwapPool).exchange(fromTokenIndex, toTokenIndex, balance, _minToAmount);
        emit TokensExchanged(_stableSwapPool, _fromToken, USDC, balance, receivedAmount);
        uint256 USDCRecoverBalance = IERC20(USDC).balanceOf(address(this));
        emit ERC20RecoveredToMainAccount(USDC, USDCRecoverBalance);
        _transferERC20ToMainAccount(USDC, USDCRecoverBalance);
    }

    /**
     * @notice Removes all Liquidity as USDC with specified slippage amount and then recovers to mainAccount
     * @param _LPToken The address of the pool to remove liquidity from.
     * @param _USDCIndex The address of the LP token and pool to recover from.
     * @param _minReceiveAmount The minimum amount of USDC to receive.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverUSDCFromLP(address _LPToken, int128 _USDCIndex, uint256 _minReceiveAmount)
        external
        nonReentrant
        requiresAuthorizedRecoveryParty
    {
        // pool address is validated by _removeSingleTokenLiquidity
        ICurveStableSwapAppBeacon appBeacon = _getAppBeacon();
        address USDC = appBeacon.USDC();

        if (ICurveStableSwapNG(_LPToken).coins(uint256(uint128(_USDCIndex))) != USDC) revert CurveAppError.TokenIndexMismatch();

        // recover funds
        uint256 lpBalance = IERC20(_LPToken).balanceOf(address(this));

        // the LP token is the pool address
        uint256 USDCRemoved = _removeSingleTokenLiquidity(_LPToken, _USDCIndex, lpBalance, _minReceiveAmount);

        emit ERC20RecoveredToMainAccount(USDC, USDCRemoved);
        _transferERC20ToMainAccount(USDC, IERC20(USDC).balanceOf(address(this)));
    }

    /**
     * @notice Removes a single token from an LP for the purpose of recovery
     * @param _LPToken The address of the LP token/pool to remove liquidity from.
     * @param _tokenIndex The index of the token to remove from the liquidity pool
     * @param _minToAmount The minimum amount of token to withdraw from the liquidity pool.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverERC20FromLP(address _LPToken, int128 _tokenIndex, uint256 _minToAmount)
        external
        nonReentrant
        requiresAuthorizedRecoveryParty
    {
        // pool address is validated by _removeSingleTokenLiquidity
        // remove token from pool
        uint256 lpBalance = IERC20(_LPToken).balanceOf(address(this));
        _removeSingleTokenLiquidity(_LPToken, _tokenIndex, lpBalance, _minToAmount);
    }

    /*///////////////////////////////////////////////////////////////
                                INTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Removes liquidity for a single token from the Curve stable swap pool.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _tokenIndex The index of the token to remove liquidity for.
     * @param _lpAmount The amount of LP tokens to burn.
     * @param _minReceiveAmount The minimum amount of tokens to receive in return.
     * @return amountRemoved The amount of tokens that were removed from the pool.
     */
    function _removeSingleTokenLiquidity(address _stableSwapPool, int128 _tokenIndex, uint256 _lpAmount, uint256 _minReceiveAmount)
        internal
        returns (uint256 amountRemoved)
    {
        _validatePoolAddress(_stableSwapPool);
        amountRemoved = ICurveStableSwapNG(_stableSwapPool).remove_liquidity_one_coin(_lpAmount, _tokenIndex, _minReceiveAmount);
        emit LiquidityRemovedSingleToken(_stableSwapPool, amountRemoved, _lpAmount);
    }

    /**
     * @notice Withdraw coins from a Curve stable swap pool in an imbalanced amount.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _lpAmount The max amount of LP tokens to be burned for the token amounts to be removed
     * @param _amounts The amounts of tokens to be removed from the pool.
     */
    function _removeLiquidityImbalance(address _stableSwapPool, uint256 _lpAmount, uint256[] calldata _amounts) internal {
        _validatePoolAddress(_stableSwapPool);
        uint256 amountLPBurnt = ICurveStableSwapNG(_stableSwapPool).remove_liquidity_imbalance(_amounts, _lpAmount);
        emit LiquidityRemoved(_stableSwapPool, _amounts, amountLPBurnt);
    }

    function _validatePoolAddress(address _stableSwapPool) internal {
        ICurveStableSwapAppBeacon appBeacon = _getAppBeacon();
        if (!appBeacon.isSupportedPool(_stableSwapPool)) revert CurveAppError.UnsupportedPool(_stableSwapPool);
        if (ICurveStableSwapFactoryNG(appBeacon.curveStableswapFactoryNG()).get_implementation_address(_stableSwapPool) == address(0))
        {
            revert CurveAppError.InvalidPoolAddress(_stableSwapPool);
        }
    }

    /**
     * @dev Returns the beacon contract for the Curve StableSwap app.
     * @return The beacon contract for the Curve StableSwap app.
     */
    function _getAppBeacon() internal view returns (ICurveStableSwapAppBeacon) {
        return (ICurveStableSwapAppBeacon(AppBase._getAppBeacon()));
    }
}

File 2 of 36 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

File 3 of 36 : ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}

File 4 of 36 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

File 5 of 36 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 6 of 36 : ERC1155Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)

pragma solidity ^0.8.20;

import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";

/**
 * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
 *
 * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
 * stuck.
 */
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
    }

    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}

File 7 of 36 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

File 8 of 36 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @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.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
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].
     *
     * CAUTION: See Security Considerations above.
     */
    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);
}

File 9 of 36 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @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.encodeCall(token.approve, (spender, value));

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

    /**
     * @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);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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(token).code.length > 0;
    }
}

File 10 of 36 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 11 of 36 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 12 of 36 : ERC721Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)

pragma solidity ^0.8.20;

import {IERC721Receiver} from "../IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
 * {IERC721-setApprovalForAll}.
 */
abstract contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

File 13 of 36 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) 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 FailedInnerCall();
        }
    }
}

File 14 of 36 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 15 of 36 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 16 of 36 : AddressError.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title Library for address related errors.
 */
library AddressError {
    /**
     * @dev Thrown when a zero address was passed as a function parameter (0x0000000000000000000000000000000000000000).
     */
    error ZeroAddress();

    /**
     * @dev Thrown when an address representing a contract is expected, but no code is found at the address.
     * @param contr The address that was expected to be a contract.
     */
    error NotAContract(address contr);
}

File 17 of 36 : ChangeError.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title Library for change related errors.
 */
library ChangeError {
    /**
     * @dev Thrown when a change is expected but none is detected.
     */
    error NoChange();
}

File 18 of 36 : IUUPSImplementation.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title Contract to be used as the implementation of a Universal Upgradeable Proxy Standard (UUPS) proxy.
 *
 * Important: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the proxy. This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.
 */
interface IUUPSImplementation {
    /**
     * @notice Thrown when an incoming implementation will not be able to receive future upgrades.
     */
    error ImplementationIsSterile(address implementation);

    /**
     * @notice Thrown intentionally when testing future upgradeability of an implementation.
     */
    error UpgradeSimulationFailed();

    /**
     * @notice Emitted when the implementation of the proxy has been upgraded.
     * @param self The address of the proxy whose implementation was upgraded.
     * @param implementation The address of the proxy's new implementation.
     */
    event Upgraded(address indexed self, address implementation);

    /**
     * @notice Allows the proxy to be upgraded to a new implementation.
     * @param newImplementation The address of the proxy's new implementation.
     * @dev Will revert if `newImplementation` is not upgradeable.
     * @dev The implementation of this function needs to be protected by some sort of access control such as `onlyOwner`.
     */
    function upgradeTo(address newImplementation) external;

    /**
     * @notice Function used to determine if a new implementation will be able to receive future upgrades in `upgradeTo`.
     * @param newImplementation The address of the new implementation being tested for future upgradeability.
     * @dev This function will always revert, but will revert with different error messages. The function `upgradeTo` uses this error to determine the future upgradeability of the implementation in question.
     */
    function simulateUpgradeTo(address newImplementation) external;

    /**
     * @notice Retrieves the current implementation of the proxy.
     * @return The address of the current implementation.
     */
    function getImplementation() external view returns (address);
}

File 19 of 36 : ProxyStorage.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

contract ProxyStorage {
    bytes32 private constant _SLOT_PROXY_STORAGE =
        keccak256(abi.encode("io.synthetix.core-contracts.Proxy"));

    struct ProxyStore {
        address implementation;
        bool simulatingUpgrade;
    }

    function _proxyStore() internal pure returns (ProxyStore storage store) {
        bytes32 s = _SLOT_PROXY_STORAGE;
        assembly {
            store.slot := s
        }
    }
}

File 20 of 36 : UUPSImplementation.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

import "../interfaces/IUUPSImplementation.sol";
import "../errors/AddressError.sol";
import "../errors/ChangeError.sol";
import "../utils/AddressUtil.sol";
import "./ProxyStorage.sol";

abstract contract UUPSImplementation is IUUPSImplementation, ProxyStorage {
    /**
     * @inheritdoc IUUPSImplementation
     */
    function simulateUpgradeTo(address newImplementation) public override {
        ProxyStore storage store = _proxyStore();

        store.simulatingUpgrade = true;

        address currentImplementation = store.implementation;
        store.implementation = newImplementation;

        (bool rollbackSuccessful, ) = newImplementation.delegatecall(
            abi.encodeCall(this.upgradeTo, (currentImplementation))
        );

        if (!rollbackSuccessful || _proxyStore().implementation != currentImplementation) {
            revert UpgradeSimulationFailed();
        }

        store.simulatingUpgrade = false;

        // solhint-disable-next-line reason-string
        revert();
    }

    /**
     * @inheritdoc IUUPSImplementation
     */
    function getImplementation() external view override returns (address) {
        return _proxyStore().implementation;
    }

    function _upgradeTo(address newImplementation) internal virtual {
        if (newImplementation == address(0)) {
            revert AddressError.ZeroAddress();
        }

        if (!AddressUtil.isContract(newImplementation)) {
            revert AddressError.NotAContract(newImplementation);
        }

        ProxyStore storage store = _proxyStore();

        if (newImplementation == store.implementation) {
            revert ChangeError.NoChange();
        }

        if (!store.simulatingUpgrade && _implementationIsSterile(newImplementation)) {
            revert ImplementationIsSterile(newImplementation);
        }

        store.implementation = newImplementation;

        emit Upgraded(address(this), newImplementation);
    }

    function _implementationIsSterile(
        address candidateImplementation
    ) internal virtual returns (bool) {
        (bool simulationReverted, bytes memory simulationResponse) = address(this).delegatecall(
            abi.encodeCall(this.simulateUpgradeTo, (candidateImplementation))
        );

        return
            !simulationReverted &&
            keccak256(abi.encodePacked(simulationResponse)) ==
            keccak256(abi.encodePacked(UpgradeSimulationFailed.selector));
    }
}

File 21 of 36 : AddressUtil.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

library AddressUtil {
    function isContract(address account) internal view returns (bool) {
        uint256 size;

        assembly {
            size := extcodesize(account)
        }

        return size > 0;
    }
}

File 22 of 36 : RequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

contract RequestTypes {
    struct Request {
        address _address;
        address _address2;
        uint256 _uint256;
        bytes32 _nonce;
        uint32 _uint32;
        bool _bool;
        bytes4 _selector;
    }
}

File 23 of 36 : AppAccountBase.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { IUUPSImplementation } from "@synthetixio/core-contracts/contracts/interfaces/IUUPSImplementation.sol";
import { UUPSImplementation } from "@synthetixio/core-contracts/contracts/proxy/UUPSImplementation.sol";

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

import { IAppAccountBase } from "src/interfaces/apps/base/IAppAccountBase.sol";
import { IAppBeaconBase } from "src/interfaces/apps/base/IAppBeaconBase.sol";

import { AppBase } from "src/apps/base/AppBase.sol";
import { AppSecurityModifiers } from "src/apps/base/AppSecurityModifiers.sol";

abstract contract AppAccountBase is
    IAppAccountBase,
    UUPSImplementation,
    AppSecurityModifiers,
    ERC165,
    ERC721Holder,
    ERC1155Holder,
    ReentrancyGuardUpgradeable
{
    /*///////////////////////////////////////////////////////////////
                                FALLBACK
    ///////////////////////////////////////////////////////////////*/

    receive() external payable { }

    /*///////////////////////////////////////////////////////////////
                                CONSTRUCTOR
    ///////////////////////////////////////////////////////////////*/

    constructor() {
        _disableInitializers();
    }

    /*///////////////////////////////////////////////////////////////
                                INITIALIZER
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Initialize the app account with the main account and the app beacon.
     * @param _mainAccount the address of the main account, this is the owner of the app.
     * @param _appBeacon the beacon for the app account.
     */
    function initialize(address _mainAccount, address _appBeacon) external virtual initializer {
        AppBase._setMainAccount(_mainAccount);
        if (!IERC165(_appBeacon).supportsInterface(type(IAppBeaconBase).interfaceId)) {
            revert InvalidAppBeacon();
        }
        AppBase._setAppBeacon(_appBeacon);
    }

    /*///////////////////////////////////////////////////////////////
                                VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, ERC1155Holder) returns (bool) {
        return interfaceId == type(IAppAccountBase).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @notice Returns the app version number of the app account.
     * @return A uint64 representing the version of the app.
     * @dev NOTE: This number must be updated whenever a new version is deployed.
     * The number should always only be incremented by 1.
     */
    function appVersion() public pure virtual returns (uint64) {
        return 1;
    }

    /**
     * @notice Get the app's main account.
     * @return The main account associated with this app.
     */
    function getMainAccount() external view returns (address) {
        return AppBase._getMainAccount();
    }

    /**
     * @notice Get the app config beacon.
     * @return The app config beacon address.
     */
    function getAppBeacon() external view returns (address) {
        return AppBase._getAppBeacon();
    }

    /*///////////////////////////////////////////////////////////////
                            MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Transfer Ether to the main account from the app account.
     * @param _amount The amount of Ether to transfer.
     */
    function transferEtherToMainAccount(uint256 _amount) external nonReentrant requiresAuthorizedOperationsParty {
        _transferEtherToMainAccount(_amount);
    }

    /**
     * @notice Transfer ERC20 tokens to the main account from the app account.
     * @param _token The address of the ERC20 token.
     * @param _amount The amount of tokens to transfer.
     */
    function transferERC20ToMainAccount(address _token, uint256 _amount) external nonReentrant requiresAuthorizedOperationsParty {
        _transferERC20ToMainAccount(_token, _amount);
    }

    /**
     * @notice Transfer ERC721 tokens to the main account from the app account.
     * @param _token The address of the ERC721 token.
     * @param _tokenId The token ID to transfer.
     */
    function transferERC721ToMainAccount(address _token, uint256 _tokenId) external nonReentrant requiresAuthorizedOperationsParty {
        _transferERC721ToMainAccount(_token, _tokenId);
    }

    /**
     * @notice Transfer ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _tokenId The token ID to transfer.
     * @param _amount The amount of tokens to transfer.
     * @param _data Additional data to pass in the transfer.
     */
    function transferERC1155ToMainAccount(address _token, uint256 _tokenId, uint256 _amount, bytes calldata _data)
        external
        nonReentrant
        requiresAuthorizedOperationsParty
    {
        _transferERC1155ToMainAccount(_token, _tokenId, _amount, _data);
    }

    /**
     * @notice Transfers batch ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _ids The IDs of the ERC1155 tokens.
     * @param _amounts The amounts of the ERC1155 tokens.
     * @param _data Data to send with the transfer.
     */
    function transferERC1155BatchToMainAccount(
        address _token,
        uint256[] calldata _ids,
        uint256[] calldata _amounts,
        bytes calldata _data
    ) external nonReentrant requiresAuthorizedOperationsParty {
        _transferERC1155BatchToMainAccount(_token, _ids, _amounts, _data);
    }

    /**
     * @notice Recovers all ether in the app account to the main account.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverEtherToMainAccount() external requiresAuthorizedRecoveryParty nonReentrant {
        emit EtherRecoveredToMainAccount(address(this).balance);
        _transferEtherToMainAccount(address(this).balance);
    }

    /**
     * @notice Recovers the full balance of an ERC20 token to the main account.
     * @param _token The address of the token to be recovered to the main account.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC20ToMainAccount(address _token) public nonReentrant requiresAuthorizedRecoveryParty {
        uint256 balance = IERC20(_token).balanceOf(address(this));
        emit ERC20RecoveredToMainAccount(_token, balance);
        _transferERC20ToMainAccount(_token, balance);
    }

    /**
     * @notice Recovers a specified ERC721 token to the main account.
     * @param _token The ERC721 token address to recover.
     * @param _tokenId The ID of the ERC721 token to recover.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC721ToMainAccount(address _token, uint256 _tokenId) external requiresAuthorizedRecoveryParty nonReentrant {
        emit ERC721RecoveredToMainAccount(_token, _tokenId);
        _transferERC721ToMainAccount(_token, _tokenId);
    }

    /**
     * @notice Recovers a specified ERC1155 token to the main account.
     * @param _token The ERC1155 token address to recover.
     * @param _tokenId The id of the token to recover.
     * @param _data The data for the transaction.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC1155ToMainAccount(address _token, uint256 _tokenId, bytes calldata _data)
        external
        requiresAuthorizedRecoveryParty
        nonReentrant
    {
        uint256 balance = IERC1155(_token).balanceOf(address(this), _tokenId);
        emit ERC1155RecoveredToMainAccount(_token, _tokenId, balance, _data);
        _transferERC1155ToMainAccount(_token, _tokenId, balance, _data);
    }

    /**
     * @notice Recovers multiple ERC1155 tokens to the main account.
     * @param _token The address of the ERC1155 token.
     * @param _tokenIds The IDs of the ERC1155 tokens.
     * @param _amounts The values of the ERC1155 tokens.
     * @param _data Data to send with the transfer.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC1155BatchToMainAccount(
        address _token,
        uint256[] calldata _tokenIds,
        uint256[] calldata _amounts,
        bytes calldata _data
    ) external requiresAuthorizedRecoveryParty nonReentrant {
        emit ERC1155BatchRecoveredToMainAccount(_token, _tokenIds, _amounts, _data);
        _transferERC1155BatchToMainAccount(_token, _tokenIds, _amounts, _data);
    }

    /**
     * @notice Upgrade to a new account implementation
     * @param _newImplementation The address of the new account implementation
     * @dev when this function is called, the UUPSImplementation contract will do
     * a simulation of the upgrade. If the simulation fails, the upgrade will not be performed.
     * So when simulatingUpgrade is true, we bypass the security logic as the way the simulation is
     * done would always revert.
     * @dev NOTE: DO NOT CALL THIS FUNCTION DIRECTLY. USE upgradeAppVersion INSTEAD.
     */
    function upgradeTo(address _newImplementation) public {
        /// @dev if we are in the middle of a simulation, then we use the default _upgradeTo function
        if (_proxyStore().simulatingUpgrade) {
            _upgradeTo(_newImplementation);
            return;
        }
        /// @dev if not in a simulation, then we perform the actual upgrade
        _upgradeToLatestImplementation(_newImplementation);
    }

    /**
     * @notice Upgrade the app account to the latest implementation and beacon.
     * @param _appBeacon The address of the new app beacon.
     * @param _latestAppImplementation The address of the latest app implementation.
     * @dev Requires the sender to be the main account.
     */
    function upgradeAppVersion(address _appBeacon, address _latestAppImplementation) external {
        if (_appBeacon != AppBase._getAppBeacon()) {
            _updateAppBeacon(_appBeacon);
        }
        if (_latestAppImplementation != IUUPSImplementation(address(this)).getImplementation()) {
            upgradeTo(_latestAppImplementation);
        }
    }

    /*///////////////////////////////////////////////////////////////
                                INTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Upgrade the account implementation to the latest version
     * @dev Checks are done in the main account
     * @dev requires the sender to be the main account
     */
    function _upgradeToLatestImplementation(address _newImplementation) internal virtual requiresMainAccountSender {
        _upgradeTo(_newImplementation);
    }

    /**
     * @notice Updates the app beacon to the latest beacon as set in the current beacon.
     * @dev requires the sender to be the main account
     */
    function _updateAppBeacon(address _newAppBeacon) internal requiresMainAccountSender {
        AppBase._setAppBeacon(_newAppBeacon);
    }

    /**
     * @notice Transfer Ether to the main account from the app account.
     * @param _amount The amount of Ether to transfer.
     */
    function _transferEtherToMainAccount(uint256 _amount) internal {
        emit EtherTransferredToMainAccount(_amount);
        (bool success,) = payable(AppBase._getMainAccount()).call{ value: _amount }("");
        if (!success) revert ETHTransferFailed();
    }

    /**
     * @notice Transfer ERC20 tokens to the main account from the app account.
     * @param _token The address of the ERC20 token.
     * @param _amount The amount of tokens to transfer.
     */
    function _transferERC20ToMainAccount(address _token, uint256 _amount) internal {
        emit ERC20TransferredToMainAccount(_token, _amount);
        SafeERC20.safeTransfer(IERC20(_token), AppBase._getMainAccount(), _amount);
    }

    /**
     * @notice Transfer ERC721 tokens to the main account from the app account.
     * @param _token The address of the ERC721 token.
     * @param _tokenId The token ID to transfer.
     */
    function _transferERC721ToMainAccount(address _token, uint256 _tokenId) internal {
        emit ERC721TransferredToMainAccount(_token, _tokenId);
        IERC721(_token).safeTransferFrom(address(this), AppBase._getMainAccount(), _tokenId);
    }

    /**
     * @notice Transfer ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _tokenId The token ID to transfer.
     * @param _amount The amount of tokens to transfer.
     * @param _data Additional data to pass in the transfer.
     */
    function _transferERC1155ToMainAccount(address _token, uint256 _tokenId, uint256 _amount, bytes calldata _data) internal {
        emit ERC1155TransferredToMainAccount(_token, _tokenId, _amount, _data);
        IERC1155(_token).safeTransferFrom(address(this), AppBase._getMainAccount(), _tokenId, _amount, _data);
    }

    /**
     * @notice Transfers multiple ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _tokenIds The IDs of the ERC1155 token.
     * @param _amounts The amounts of tokens to transfer.
     * @param _data Data to send with the transfer.
     */
    function _transferERC1155BatchToMainAccount(
        address _token,
        uint256[] calldata _tokenIds,
        uint256[] calldata _amounts,
        bytes calldata _data
    ) internal {
        emit ERC1155BatchTransferredToMainAccount(_token, _tokenIds, _amounts, _data);
        IERC1155(_token).safeBatchTransferFrom(address(this), AppBase._getMainAccount(), _tokenIds, _amounts, _data);
    }
}

File 24 of 36 : AppBase.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import { Error } from "src/libraries/Error.sol";

/**
 * @title AppBase storage struct
 */
library AppBase {
    struct Data {
        address mainAccount; // main account address
        address appBeacon; // Address of beacon for app configuration
    }

    /*///////////////////////////////////////////////////////////////
                    			EVENTS / ERRORS
    ///////////////////////////////////////////////////////////////*/

    event MainAccountSet(address mainAccount);
    event AppBeaconSet(address appBeacon);

    /**
     * @dev Returns the account stored at the specified account id.
     */
    function getStorage() internal pure returns (Data storage data) {
        bytes32 s = keccak256(abi.encode("io.infinex.AppBase"));
        assembly {
            data.slot := s
        }
    }

    /*///////////////////////////////////////////////////////////////
                                VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Get the Main Account.
     * @return The Main Account address.
     */
    function _getMainAccount() internal view returns (address) {
        Data storage data = getStorage();
        return data.mainAccount;
    }

    /**
     * @notice Get the App Beacon.
     * @return The App Beacon.
     */
    function _getAppBeacon() internal view returns (address) {
        Data storage data = getStorage();
        return data.appBeacon;
    }

    /*///////////////////////////////////////////////////////////////
                                MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Set the Main Account address.
     * @param _mainAccount The address to be set as Main Account.
     */
    function _setMainAccount(address _mainAccount) internal {
        Data storage data = getStorage();
        if (_mainAccount == address(0)) revert Error.NullAddress();
        emit MainAccountSet(_mainAccount);
        data.mainAccount = _mainAccount;
    }

    /**
     * @notice Set an app beacon for the account.
     * @param _appBeacon The app beacon associated with the account.
     */
    function _setAppBeacon(address _appBeacon) internal {
        Data storage data = getStorage();
        if (_appBeacon == address(0)) revert Error.NullAddress();
        emit AppBeaconSet(_appBeacon);
        data.appBeacon = _appBeacon;
    }
}

File 25 of 36 : AppERC2771Context.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// SPDX-License-Identifier: MIT
// Originally sourced from OpenZeppelin Contracts (last updated v4.9.3) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.21;

import { AppBase } from "src/apps/base/AppBase.sol";
import { IBaseModule } from "src/interfaces/accounts/IBaseModule.sol";

/**
 * @dev Context variant with ERC2771 support.
 */
library AppERC2771Context {
    function _msgSender() internal view returns (address) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (_isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
        } else {
            return msg.sender;
        }
    }

    // slither-disable-start dead-code
    function _msgData() internal view returns (bytes calldata) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (_isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return msg.data[:calldataLength - contextSuffixLength];
        } else {
            return msg.data;
        }
    }

    /**
     * @notice Checks if a forwarder is trusted.
     * @param forwarder The address of the forwarder to check.
     * @return A boolean indicating whether the forwarder is trusted or not.
     */
    function _isTrustedForwarder(address forwarder) internal view returns (bool) {
        return IBaseModule(AppBase._getMainAccount()).isTrustedForwarder(forwarder);
    }

    /**
     * @dev ERC-2771 specifies the context as being a single address (20 bytes).
     */
    function _contextSuffixLength() internal pure returns (uint256) {
        return 20;
    }
    // slither-disable-end dead-code
}

File 26 of 36 : AppSecurityModifiers.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import { AppERC2771Context } from "src/apps/base/AppERC2771Context.sol";
import { AppBase } from "src/apps/base/AppBase.sol";

import { IAccountUtilsModule } from "src/interfaces/accounts/IAccountUtilsModule.sol";

contract AppSecurityModifiers {
    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    error InvalidKeySignature(address from);

    /*///////////////////////////////////////////////////////////////
                            SECURITY CHECK MODIFIERS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Modifier to check if the sender is the main account.
     */
    modifier requiresMainAccountSender() {
        if (msg.sender != AppBase._getMainAccount()) {
            revert InvalidKeySignature(msg.sender);
        }

        _;
    }

    /**
     * @notice Modifier to check if the sender is an sudo key.
     */
    modifier requiresSudoKeySender() {
        if (!_isValidSudoKey(AppERC2771Context._msgSender())) {
            revert InvalidKeySignature(AppERC2771Context._msgSender());
        }

        _;
    }

    /**
     * @notice Modifier to check if the sender is a sudo or operation key.
     * If not, it reverts with an error message.
     */
    modifier requiresAuthorizedOperationsParty() {
        if (!_isAuthorizedOperationsParty(AppERC2771Context._msgSender())) {
            revert InvalidKeySignature(AppERC2771Context._msgSender());
        }

        _;
    }

    /**
     * @notice Modifier to check if the sender is an sudo key, a recovery key or a trusted recovery keeper.
     * If not, it reverts with an error message.
     */
    modifier requiresAuthorizedRecoveryParty() {
        if (!_isAuthorizedRecoveryParty(AppERC2771Context._msgSender())) {
            revert InvalidKeySignature(AppERC2771Context._msgSender());
        }

        _;
    }

    /**
     * @notice Validate with the parent account if a key is a sudoKey.
     * @param _key The key to check.
     */
    function _isValidSudoKey(address _key) internal view returns (bool) {
        return IAccountUtilsModule(AppBase._getMainAccount()).isValidSudoKey(_key);
    }

    /**
     * @notice Validate with the parent account if a key is an authorized operations party.
     * @param _key The key to check.
     */
    function _isAuthorizedOperationsParty(address _key) internal view returns (bool) {
        return IAccountUtilsModule(AppBase._getMainAccount()).isAuthorizedOperationsParty(_key);
    }

    /**
     * @notice Validate with the parent account if a key is an authorized recovery party.
     * @param _key The key to check.
     */
    function _isAuthorizedRecoveryParty(address _key) internal view returns (bool) {
        return IAccountUtilsModule(AppBase._getMainAccount()).isAuthorizedRecoveryParty(_key);
    }
}

File 27 of 36 : CurveAppError.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library CurveAppError {
    /*///////////////////////////////////////////////////////////////
                                GENERIC
    ///////////////////////////////////////////////////////////////*/

    error TokenIndexMismatch();
    error InvalidPoolAddress(address poolAddress);
    error UnsupportedPool(address poolAddress);
    error InvalidToken();
    error ZeroAddress();
}

File 28 of 36 : IAccountUtilsModule.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

interface IAccountUtilsModule {
    event AccountInfinexProtocolBeaconImplementationUpgraded(address infinexProtocolConfigBeacon);

    event AccountSynthetixInformationBeaconUpgraded(address synthetixInformationBeacon);

    event AccountCircleBridgeParamsUpgraded(address circleBridge, address circleMinter, uint32 defaultDestinationCCTPDomain);

    event AccountWormholeCircleBridgeParamsUpgraded(address wormholeCircleBridge, uint16 defaultDestinationWormholeChainId);

    event AccountUSDCAddressUpgraded(address USDC);

    /*///////////////////////////////////////////////////////////////
                                    VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Get the Infinex Protocol Config
     * @return The Infinex Protocol Config Beacon
     */
    function infinexProtocolConfigBeacon() external view returns (address);

    /**
     * @notice Check if the provided operation key is valid
     * @param _operationKey The operation key to check
     * @return A boolean indicating if the key is valid
     */
    function isValidOperationKey(address _operationKey) external view returns (bool);

    /**
     * @notice Check if the provided sudo key is valid
     * @param _sudoKey The sudo key to check
     * @return A boolean indicating if the sudo key is valid
     */
    function isValidSudoKey(address _sudoKey) external view returns (bool);

    /**
     * @notice Check if the provided recovery key is valid
     * @param _recoveryKey The recovery key to check
     * @return A boolean indicating if the recovery key is valid
     */
    function isValidRecoveryKey(address _recoveryKey) external view returns (bool);

    /**
     * @notice Checks if the given address is an authorized operations party.
     * @param _key The address to check.
     * @return A boolean indicating whether the address is an authorized operations party.
     * @dev Update this function whenever the logic for requiresAuthorizedOperationsParty
     * from SecurityModifiers changes
     */
    function isAuthorizedOperationsParty(address _key) external view returns (bool);

    /**
     * @notice Checks if the given address is an authorized recovery party.
     * @param _key The address to check.
     * @return A boolean indicating whether the address is an authorized recovery party.
     * @dev Update this function whenever the logic for requiresAuthorizedRecoveryParty
     * from SecurityModifiers changes
     */
    function isAuthorizedRecoveryParty(address _key) external view returns (bool);

    /**
     * @notice Retrieves the Circle Bridge parameters.
     * @return The address of the circleBridge
     * @return The address of the minter.
     * @return The default circle bridge destination domain.
     */
    function getCircleBridgeParams() external view returns (address, address, uint32);

    /**
     * @notice Retrieves the wormhole circle bridge
     * @return The wormhole circle bridge address.
     */
    function getWormholeCircleBridge() external view returns (address);

    /**
     * @notice Retrieves the Wormhole Circle Bridge parameters.
     * @return The address of the wormholeCircleBridge
     * @return The address of the wormholeCircleBridge and the default defaultDestinationWormholeChainId
     */
    function getWormholeCircleBridgeParams() external view returns (address, uint16);

    /**
     * @notice Retrieves the USDC address.
     * @return The address of USDC
     */
    function getUSDCAddress() external view returns (address);

    /**
     * @notice Retrieves the maximum withdrawal fee.
     * @return The maximum withdrawal fee.
     */
    function getMaxWithdrawalFee() external pure returns (uint256);

    /*///////////////////////////////////////////////////////////////
                                MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Upgrade to a new beacon implementation and updates any new parameters along with it
     * @param _newInfinexProtocolConfigBeacon The address of the new beacon
     * @dev requires the sender to be the sudo key
     * @dev Requires passing the new beacon address which matches the latest to ensure that the upgrade both
     * is as the user intended, and is to the latest beacon implementation. Prevents the user from opting in to a
     * specific version and upgrading to a later version that may have been deployed between the opt-in and the upgrade
     */
    function upgradeProtocolBeaconParameters(address _newInfinexProtocolConfigBeacon) external;

    /**
     * @notice Updates the parameters for the Circle Bridge to the latest from the Infinex Protocol Config Beacon.
     * Update is opt in to prevent malicious automatic updates.
     * @dev requires the sender to be the sudo key
     */
    function updateCircleBridgeParams() external;

    /**
     * @notice Updates the parameters for the Wormhole Circle Bridge to the latest from the Infinex Protocol Config Beacon.
     * Update is opt in to prevent malicious automatic updates.
     * @dev requires the sender to be the sudo key
     */
    function updateWormholeCircleBridge() external;

    /**
     * @notice Updates the USDC address from the Infinex Protocol Config Beacon.
     * Update is opt in to prevent malicious automatic updates.
     * @dev requires the sender to be the sudo key
     */
    function updateUSDCAddress() external;
}

File 29 of 36 : IBaseModule.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import { RequestTypes } from "src/accounts/utils/RequestTypes.sol";

interface IBaseModule {
    /*///////////////////////////////////////////////////////////////
                    			EVENTS / ERRORS
    ///////////////////////////////////////////////////////////////*/

    event AccountImplementationUpgraded(address accountImplementation);
    event AccountMigratedFrom(uint64 previousVersion, uint64 currentVersion);

    /*///////////////////////////////////////////////////////////////
                                 		INITIALIZER
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Initialize the account with the sudo key
     */
    function initialize(address _sudoKey) external;

    /**
     * @notice Reinitialize the account with the current version
     * @dev Only to be called by the upgradeTo function
     */
    function reinitialize(uint64 _previousVersion) external;

    /**
     * @notice Reinitialize the account with the current version
     * @dev Only to be called once to reinitialize accounts created with v1
     */
    function reinitializeLegacyAccount() external;

    /*///////////////////////////////////////////////////////////////
                                    VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Returns the version number of the account.
     * @return A uint64 representing the version of the account.
     * @dev The version number is provided by the OZ Initializable library
     */
    function accountVersion() external view returns (uint64);

    /**
     * @notice Check if the provided nonce is valid
     * @param _nonce The nonce to check
     * @return A boolean indicating if the nonce is valid
     */
    function isValidNonce(bytes32 _nonce) external view returns (bool);

    /**
     * @notice Check if the provided forwarder is trusted
     * @param _forwarder The forwarder to check
     * @return A boolean indicating if the forwarder is trusted
     */
    function isTrustedForwarder(address _forwarder) external view returns (bool);

    /**
     * @notice Get all trusted forwarders
     * @return An array of addresses of all trusted forwarders
     */
    function trustedForwarders() external view returns (address[] memory);

    /*///////////////////////////////////////////////////////////////
                    			MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Enables or disables an operation key for the account
     * @param _operationKey The address of the operation key to be set
     * @param _isValid Whether the key is to be set as valid or invalid
     * @dev This function requires the sender to be the sudo key holder
     */
    function setOperationKeyStatus(address _operationKey, bool _isValid) external;

    /**
     * @notice Enables or disables a recovery key for the account
     * @param _recoveryKey The address of the recovery key to be set
     * @param _isValid Whether the key is to be set as valid or invalid
     * @dev This function requires the sender to be the sudo key holder
     */
    function setRecoveryKeyStatus(address _recoveryKey, bool _isValid) external;

    /**
     * @notice Enables or disables a sudo key for the account
     * @param _sudoKey The address of the sudo key to be set
     * @param _isValid Whether the key is to be set as valid or invalid
     * @dev This function requires the sender to be the sudo key holder
     */
    function setSudoKeyStatus(address _sudoKey, bool _isValid) external;

    /**
     * @notice Add a new trusted forwarder
     * @param _request The Request struct containing:
     *  RequestData {
     *  address _address; - The address of the new trusted forwarder.
     *	bytes32 _nonce; - The nonce of the signature
     *  }
     * @param _signature The required signature for executing the transaction
     * Required signature:
     * - sudo key
     */
    function addTrustedForwarder(RequestTypes.Request calldata _request, bytes calldata _signature) external;

    /**
     * @notice Remove a trusted forwarder
     * @param _request The Request struct containing:
     *  RequestData {
     *  address _address; - The address of the trusted forwarder to be removed.
     *	bytes32 _nonce; - The nonce of the signature
     *  }
     * @param _signature The required signature for executing the transaction
     * Required signature:
     * - sudo key
     */
    function removeTrustedForwarder(RequestTypes.Request calldata _request, bytes calldata _signature) external;
}

File 30 of 36 : IAppAccountBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/**
 * @title IAppAccountBase
 * @notice Interface for the App Account Base
 */
interface IAppAccountBase {
    /*///////////////////////////////////////////////////////////////
    	 						EVENTS
    ///////////////////////////////////////////////////////////////*/

    event EtherTransferredToMainAccount(uint256 amount);
    event ERC20TransferredToMainAccount(address indexed token, uint256 amount);
    event ERC721TransferredToMainAccount(address indexed token, uint256 tokenId);
    event ERC1155TransferredToMainAccount(address indexed token, uint256 tokenId, uint256 amount, bytes data);
    event ERC1155BatchTransferredToMainAccount(address indexed token, uint256[] _ids, uint256[] _values, bytes _data);
    event EtherRecoveredToMainAccount(uint256 amount);
    event ERC20RecoveredToMainAccount(address indexed token, uint256 amount);
    event ERC721RecoveredToMainAccount(address indexed token, uint256 tokenId);
    event ERC1155RecoveredToMainAccount(address indexed token, uint256 tokenId, uint256 amount, bytes data);
    event ERC1155BatchRecoveredToMainAccount(address indexed token, uint256[] tokenIds, uint256[] amounts, bytes _data);

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    error InvalidAppBeacon();
    error ImplementationMismatch(address implementation, address latestImplementation);
    error ETHTransferFailed();

    /*///////////////////////////////////////////////////////////////
                                 		INITIALIZER
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Initialize the app account with the main account and the app beacon.
     * @param _mainAccount the address of the main account, this is the owner of the app.
     * @param _appBeacon the beacon for the app account.
     */
    function initialize(address _mainAccount, address _appBeacon) external;

    /*///////////////////////////////////////////////////////////////
                    			VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Returns the app version number of the app account.
     * @return A uint64 representing the version of the app.
     * @dev NOTE: This number must be updated whenever a new version is deployed.
     * The number should always only be incremented by 1.
     */
    function appVersion() external pure returns (uint64);

    /**
     * @notice Get the app's main account.
     * @return The main account associated with this app.
     */
    function getMainAccount() external view returns (address);

    /**
     * @notice Get the app config beacon.
     * @return The app config beacon address.
     */
    function getAppBeacon() external view returns (address);

    /*///////////////////////////////////////////////////////////////
                    			MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Transfer Ether to the main account from the app account.
     * @param _amount The amount of Ether to transfer.
     */
    function transferEtherToMainAccount(uint256 _amount) external;

    /**
     * @notice Transfer ERC20 tokens to the main account from the app account.
     * @param _token The address of the ERC20 token.
     * @param _amount The amount of tokens to transfer.
     */
    function transferERC20ToMainAccount(address _token, uint256 _amount) external;

    /**
     * @notice Transfer ERC721 tokens to the main account from the app account.
     * @param _token The address of the ERC721 token.
     * @param _tokenId The ID of the ERC721 token.
     */
    function transferERC721ToMainAccount(address _token, uint256 _tokenId) external;

    /**
     * @notice Transfer ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _tokenId The ID of the ERC1155 token.
     * @param _amount The amount of tokens to transfer.
     * @param _data Data to send with the transfer.
     */
    function transferERC1155ToMainAccount(address _token, uint256 _tokenId, uint256 _amount, bytes calldata _data) external;

    /**
     * @notice Transfers batch ERC1155 tokens to the main account from the app account.
     * @param _token The address of the ERC1155 token.
     * @param _ids The IDs of the ERC1155 tokens.
     * @param _amounts The amounts of the ERC1155 tokens.
     * @param _data Data to send with the transfer.
     */
    function transferERC1155BatchToMainAccount(
        address _token,
        uint256[] calldata _ids,
        uint256[] calldata _amounts,
        bytes calldata _data
    ) external;

    /**
     * @notice Recovers all ether in the app account to the main account.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverEtherToMainAccount() external;

    /**
     * @notice Recovers the full balance of an ERC20 token to the main account.
     * @param _token The address of the token to be recovered to the main account.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC20ToMainAccount(address _token) external;

    /**
     * @notice Recovers a specified ERC721 token to the main account.
     * @param _token The ERC721 token address to recover.
     * @param _tokenId The ID of the ERC721 token to recover.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC721ToMainAccount(address _token, uint256 _tokenId) external;

    /**
     * @notice Recovers all the tokens of a specified ERC1155 token to the main account.
     * @param _token The ERC1155 token address to recover.
     * @param _tokenId The id of the token to recover.
     * @param _data The data for the transaction.
     * @dev Requires the sender to be an authorized recovery party.
     */
    function recoverERC1155ToMainAccount(address _token, uint256 _tokenId, bytes calldata _data) external;

    /**
     * @notice Recovers batch ERC1155 tokens to the main account.
     * @param _token The address of the ERC1155 token.
     * @param _ids The IDs of the ERC1155 tokens.
     * @param _values The values of the ERC1155 tokens.
     * @param _data Data to send with the transfer.
     */
    function recoverERC1155BatchToMainAccount(
        address _token,
        uint256[] calldata _ids,
        uint256[] calldata _values,
        bytes calldata _data
    ) external;

    /**
     * @notice Upgrade the app account to the latest implementation and beacon.
     * @param _appBeacon The address of the new app beacon.
     * @param _latestAppImplementation The address of the latest app implementation.
     * @dev Requires the sender to be the main account.
     */
    function upgradeAppVersion(address _appBeacon, address _latestAppImplementation) external;
}

File 31 of 36 : IAppBeaconBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/**
 * @title IAppBeaconBase
 * @notice Interface for the App Beacon Base
 */
interface IAppBeaconBase {
    /*///////////////////////////////////////////////////////////////
    	 						STRUCTS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Struct containing the config for the app beacon.
     * @param appName The name of the app.
     * @param latestAppImplementation The address of the latest app implementation.
     * @param latestAppBeacon The address of the latest app beacon.
     */
    struct AppBeaconConfig {
        string appName;
        address latestAppImplementation;
        address latestAppBeacon;
    }

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    error ZeroAddress();
    error InvalidAppAccountImplementation();
    error InvalidAppBeacon();

    /*///////////////////////////////////////////////////////////////
    	 						EVENTS
    ///////////////////////////////////////////////////////////////*/

    event LatestAppImplementationSet(address latestAppImplementation);
    event LatestAppBeaconSet(address latestAppBeacon);

    /*///////////////////////////////////////////////////////////////
                    			VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Gets the name of the app associated to the beacon.
     * @return The name of the app beacon.
     */
    function getAppName() external view returns (string memory);

    /**
     * @notice Gets the latest app implementation.
     * @return The address of the latest app implementation.
     */
    function getLatestAppImplementation() external view returns (address);

    /**
     * @notice Gets the latest beacon address for the app.
     * @return The address of the latest app beacon.
     */
    function getLatestAppBeacon() external view returns (address);

    /*///////////////////////////////////////////////////////////////
                    		    MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Sets the latest app implementation address.
     * @param _latestAppImplementation The address of the latest implementation for the app.
     */
    function setLatestAppImplementation(address _latestAppImplementation) external;

    /**
     * @notice Sets the latest app beacon address.
     * @param _latestAppBeacon The address of the latest app beacon associated with the app.
     */
    function setLatestAppBeacon(address _latestAppBeacon) external;
}

File 32 of 36 : ICurveStableSwapApp.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/**
 * @title ICurveStableSwapApp
 * @notice Interface for the curve stable swap app.
 */
interface ICurveStableSwapApp {
    /*///////////////////////////////////////////////////////////////
    	 					    EVENTS
    ///////////////////////////////////////////////////////////////*/

    event TokensExchanged(address indexed stableSwapPool, address fromToken, address toToken, uint256 fromAmount, uint256 toAmount);
    event LiquidityAdded(address indexed stableSwapPool, uint256[] amounts, uint256 lpAmount);
    event LiquidityRemoved(address indexed stableSwapPool, uint256[] amounts, uint256 lpAmount);
    event LiquidityRemovedSingleToken(address indexed stableSwapPool, uint256 amountRemoved, uint256 lpAmountBurnt);

    /*///////////////////////////////////////////////////////////////
                    			MUTATIVE FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Allows the authorized operations party to exchange tokens on the stable swap pool.
     * @param _stableSwapPool The address of the stable swap pool.
     * @param _fromToken The address of the ERC20 token provided to exchange.
     * @param _toToken The address of the ERC20 token to receive from the exchange.
     * @param _fromAmount The amount of tokens to exchange.
     * @param _minToAmount The minimum amount of tokens to receive.
     */
    function exchange(address _stableSwapPool, address _fromToken, address _toToken, uint256 _fromAmount, uint256 _minToAmount)
        external;

    /**
     * @notice Adds liquidity to the specified pool
     * @dev The arrays indices have to match the indices of the tokens in the pool.
     * @param _stableSwapPool The address of the pool to add liquidity to.
     * @param _tokens An array of token addresses to add as liquidity.
     * @param _amounts An array of token amounts to add as liquidity.
     * @param _minLPAmount The minimum amount of LP tokens to receive.
     */
    function addLiquidity(address _stableSwapPool, address[] calldata _tokens, uint256[] calldata _amounts, uint256 _minLPAmount)
        external;

    /**
     * @notice Removes liquidity for a single token from the Curve stable swap pool.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _tokenIndex The index of the token to remove liquidity.
     * @param _lpAmount The amount of LP tokens to burn.
     * @param _minReceiveAmount The minimum amount of tokens to receive in return.
     * @return The amount of tokens received after removing liquidity.
     */
    function removeSingleTokenLiquidity(address _stableSwapPool, int128 _tokenIndex, uint256 _lpAmount, uint256 _minReceiveAmount)
        external
        returns (uint256);

    /**
     * @notice Withdraw coins from a Curve stable swap pool in an imbalanced amount.
     * @param _stableSwapPool The address of the Curve stable swap pool.
     * @param _lpAmount The max amount of LP tokens to burn.
     * @param _amounts The amount of tokens to receive in return.
     */
    function removeLiquidityImbalance(address _stableSwapPool, uint256 _lpAmount, uint256[] calldata _amounts) external;

    /**
     * @notice Swaps ERC20 tokens to USDC at the current exchange amount and then recovers to mainAccount
     * @param _stableSwapPool The address of the stable swap pool.
     * @param _fromToken The address of the ERC20 token to recover.
     * @param _minToAmount The minimum amount of USDC to receive.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverERC20ToUSDC(address _stableSwapPool, address _fromToken, uint256 _minToAmount) external;

    /**
     * @notice Removes all Liquidity as USDC with specified slippage amount and then recovers to mainAccount
     * @param _LPToken The address of the pool to remove liquidity from.
     * @param _USDCIndex The address of the LP token and pool to recover from.
     * @param _minReceiveAmount The minimum amount of USDC to receive.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverUSDCFromLP(address _LPToken, int128 _USDCIndex, uint256 _minReceiveAmount) external;

    /**
     * @notice Removes a single token from an LP for the purpose of recovery
     * @param _LPToken The address of the LP token/pool to remove liquidity from.
     * @param _tokenIndex The index of the token to remove from the liquidity pool
     * @param _minToAmount The minimum amount of token to withdraw from the liquidity pool.
     * @dev This function must be called by an authorized recovery party.
     */
    function recoverERC20FromLP(address _LPToken, int128 _tokenIndex, uint256 _minToAmount) external;
}

File 33 of 36 : ICurveStableSwapAppBeacon.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

/**
 * @title ICurveStableSwapAppBeacon
 * @notice Interface for the curve app beacon.
 */
interface ICurveStableSwapAppBeacon {
    /*///////////////////////////////////////////////////////////////
    	 				        STRUCTS
    ///////////////////////////////////////////////////////////////*/

    struct PoolData {
        address pool;
        int128 fromTokenIndex;
        int128 toTokenIndex;
        uint256 amountReceived;
        address[] tokens;
        uint256[] balances;
        uint256[] decimals;
        bool isUnderlying;
    }

    /*///////////////////////////////////////////////////////////////
    	 				    VIEW FUNCTIONS/VARIABLES
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Gets the curve stable swap factory address.
     * @return The address of the curve stable swap factory.
     */
    function curveStableswapFactoryNG() external view returns (address);

    /**
     * @notice Gets the USDC address.
     * @return The address of the USDC token.
     */
    function USDC() external view returns (address);

    /**
     * @notice Checks if a pool has been vetted by the council and can be safely used by the app
     * @param _pool The address of the pool.
     * @return True if the pool is supported, false otherwise.
     */
    function isSupportedPool(address _pool) external view returns (bool);

    /**
     * @notice Get the pool data for the given tokens. Data will be empty if type is underyling
     * @param _fromToken The address of the token to swap from.
     * @param _toToken The address of the token to swap to.
     * @return poolData The pool data for the given tokens.
     */
    function getPoolDatafromTokens(address _fromToken, address _toToken, uint256 _fromAmount)
        external
        returns (PoolData memory poolData);

    /**
     * @notice A safety feature to limit the pools that can be used by the app to only vetted and suppported pools
     * @dev Only the contract owner can call this function.
     * @param _pool The address of the pool.
     * @param _supported The supported status of the pool.
     */
    function setIsSupportedPool(address _pool, bool _supported) external;
}

File 34 of 36 : ICurveStableSwapFactoryNG.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

// from https://github.com/curvefi/stableswap-ng

/**
 * @title ICurveStableSwapFactoryNG
 * @notice Interface for the curve stable swap factory.
 */
interface ICurveStableSwapFactoryNG {
    /**
     * @notice Find an available pool for exchanging two coins
     * @param _from Address of coin to be sent
     * @param _to Address of coin to be received
     * @param i Index value. When multiple pools are available
     *        this value is used to return the n'th address.
     * @return Pool address
     */
    function find_pool_for_coins(address _from, address _to, uint256 i) external view returns (address);

    /**
     * @notice Find an available pool for exchanging two coins
     * @param _from Address of coin to be sent
     * @param _to Address of coin to be received
     * @return Pool address
     */
    function find_pool_for_coins(address _from, address _to) external view returns (address);

    /**
     * @notice Get the base pool for a given factory metapool
     * @param _pool Metapool address
     * @return Address of base pool
     */
    function get_base_pool(address _pool) external view returns (address);

    /**
     * @notice Get the number of coins in a pool
     * @param _pool Pool address
     * @return Number of coins
     */
    function get_n_coins(address _pool) external view returns (uint256);

    /**
     * @notice Get the coins within a pool
     * @param _pool Pool address
     * @return List of coin addresses
     */
    function get_coins(address _pool) external view returns (address[] memory);

    /**
     * @notice Get the underlying coins within a pool
     * @dev Reverts if a pool does not exist or is not a metapool
     * @param _pool Pool address
     * @return List of coin addresses
     */
    function get_underlying_coins(address _pool) external view returns (address[] memory);

    /**
     * @notice Get decimal places for each coin within a pool
     * @param _pool Pool address
     * @return uint256 list of decimals
     */
    function get_decimals(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Get decimal places for each underlying coin within a pool
     * @param _pool Pool address
     * @return uint256 list of decimals
     */
    function get_underlying_decimals(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Get rates for coins within a metapool
     * @param _pool Pool address
     * @return Rates for each coin, precision normalized to 10**18
     */
    function get_metapool_rates(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Get balances for each coin within a pool
     * @dev For pools using lending, these are the wrapped coin balances
     * @param _pool Pool address
     * @return uint256 list of balances
     */
    function get_balances(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Get balances for each underlying coin within a metapool
     * @param _pool Metapool address
     * @return uint256 list of underlying balances
     */
    function get_underlying_balances(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Get the amplfication co-efficient for a pool
     * @param _pool Pool address
     * @return uint256 A
     */
    function get_A(address _pool) external view returns (uint256);

    /**
     * @notice Get the fees for a pool
     * @dev Fees are expressed as integers
     * @param _pool Pool address
     * @return Pool fee and admin fee as uint256 with 1e10 precision
     */
    function get_fees(address _pool) external view returns (uint256, uint256);

    /**
     * @notice Get the current admin balances (uncollected fees) for a pool
     * @param _pool Pool address
     * @return List of uint256 admin balances
     */
    function get_admin_balances(address _pool) external view returns (uint256[] memory);

    /**
     * @notice Convert coin addresses to indices for use with pool methods
     * @param _pool Pool address
     * @param _from Coin address to be used as `i` within a pool
     * @param _to Coin address to be used as `j` within a pool
     * @return int128 `i`, int128 `j`, boolean indicating if `i` and `j` are underlying coins
     */
    function get_coin_indices(address _pool, address _from, address _to) external view returns (int128, int128, bool);

    /**
     * @notice Get the address of the liquidity gauge contract for a factory pool
     * @dev Returns `empty(address)` if a gauge has not been deployed
     * @param _pool Pool address
     * @return Implementation contract address
     */
    function get_gauge(address _pool) external view returns (address);

    /**
     * @notice Get the address of the implementation contract used for a factory pool
     * @param _pool Pool address
     * @return Implementation contract address
     */
    function get_implementation_address(address _pool) external view returns (address);

    /**
     * @notice Verify `_pool` is a metapool
     * @param _pool Pool address
     * @return True if `_pool` is a metapool
     */
    function is_meta(address _pool) external view returns (bool);

    /**
     * @notice Query the asset type of `_pool`
     * @param _pool Pool Address
     * @return Dynarray of uint8 indicating the pool asset type
     *         Asset Types:
     *             0. Standard ERC20 token with no additional features
     *             1. Oracle - token with rate oracle (e.g. wrapped staked ETH)
     *             2. Rebasing - token with rebase (e.g. staked ETH)
     *             3. ERC4626 - e.g. sDAI
     */
    function get_pool_asset_types(address _pool) external view returns (uint8[] memory);

    /**
     * @notice Deploy a new plain pool
     * @param _name Name of the new plain pool
     * @param _symbol Symbol for the new plain pool - will be
     *                concatenated with factory symbol
     * @param _coins List of addresses of the coins being used in the pool.
     * @param _A Amplification co-efficient - a lower value here means
     *           less tolerance for imbalance within the pool's assets.
     *           Suggested values include:
     *            * Uncollateralized algorithmic stablecoins: 5-10
     *            * Non-redeemable, collateralized assets: 100
     *            * Redeemable assets: 200-400
     * @param _fee Trade fee, given as an integer with 1e10 precision. The
     *             maximum is 1% (100000000). 50% of the fee is distributed to veCRV holders.
     * @param _offpeg_fee_multiplier Off-peg fee multiplier
     * @param _ma_exp_time Averaging window of oracle. Set as time_in_seconds / ln(2)
     *                     Example: for 10 minute EMA, _ma_exp_time is 600 / ln(2) ~= 866
     * @param _implementation_idx Index of the implementation to use
     * @param _asset_types Asset types for pool, as an integer
     * @param _method_ids Array of first four bytes of the Keccak-256 hash of the function signatures
     *                    of the oracle addresses that gives rate oracles.
     *                    Calculated as: keccak(text=event_signature.replace(" ", ""))[:4]
     * @param _oracles Array of rate oracle addresses.
     * @return Address of the deployed pool
     */
    function deploy_plain_pool(
        string memory _name,
        string memory _symbol,
        address[] memory _coins,
        uint256 _A,
        uint256 _fee,
        uint256 _offpeg_fee_multiplier,
        uint256 _ma_exp_time,
        uint256 _implementation_idx,
        uint8[] memory _asset_types,
        bytes4[] memory _method_ids,
        address[] memory _oracles
    ) external returns (address);
    /**
     * @notice Deploy a new metapool
     * @param _base_pool Address of the base pool to use
     *                   within the metapool
     * @param _name Name of the new metapool
     * @param _symbol Symbol for the new metapool - will be
     *                concatenated with the base pool symbol
     * @param _coin Address of the coin being used in the metapool
     * @param _A Amplification co-efficient - a higher value here means
     *           less tolerance for imbalance within the pool's assets.
     *           Suggested values include:
     *            * Uncollateralized algorithmic stablecoins: 5-10
     *            * Non-redeemable, collateralized assets: 100
     *            * Redeemable assets: 200-400
     * @param _fee Trade fee, given as an integer with 1e10 precision. The
     *             the maximum is 1% (100000000).
     *             50% of the fee is distributed to veCRV holders.
     * @param _offpeg_fee_multiplier Off-peg fee multiplier
     * @param _ma_exp_time Averaging window of oracle. Set as time_in_seconds / ln(2)
     *                     Example: for 10 minute EMA, _ma_exp_time is 600 / ln(2) ~= 866
     * @param _implementation_idx Index of the implementation to use
     * @param _asset_type Asset type for token, as an integer
     * @param _method_id  First four bytes of the Keccak-256 hash of the function signatures
     *                    of the oracle addresses that gives rate oracles.
     *                    Calculated as: keccak(text=event_signature.replace(" ", ""))[:4]
     * @param _oracle Rate oracle address.
     * @return Address of the deployed pool
     */
    function deploy_metapool(
        address _base_pool,
        string memory _name,
        string memory _symbol,
        address _coin,
        uint256 _A,
        uint256 _fee,
        uint256 _offpeg_fee_multiplier,
        uint256 _ma_exp_time,
        uint256 _implementation_idx,
        uint8 _asset_type,
        bytes4 _method_id,
        address _oracle
    ) external returns (address);
    /**
     * @notice Deploy a liquidity gauge for a factory pool
     * @param _pool Factory pool address to deploy a gauge for
     * @return Address of the deployed gauge
     */
    function deploy_gauge(address _pool) external returns (address);

    /**
     * @notice Add a base pool to the registry, which may be used in factory metapools
     * @dev 1. Only callable by admin
     *      2. Rebasing tokens are not allowed in the base pool.
     *      3. Do not add base pool which contains native tokens (e.g. ETH).
     *      4. As much as possible: use standard ERC20 tokens.
     *      Should you choose to deviate from these recommendations, audits are advised.
     * @param _base_pool Pool address to add
     * @param _base_lp_token LP token of the base pool
     * @param _asset_types Asset type for pool, as an integer
     * @param _n_coins Number of coins in the pool
     */
    function add_base_pool(address _base_pool, address _base_lp_token, uint8[] memory _asset_types, uint256 _n_coins) external;

    /**
     * @notice Set implementation contracts for pools
     * @dev Only callable by admin
     * @param _implementation_index Implementation index where implementation is stored
     * @param _implementation Implementation address to use when deploying plain pools
     */
    function set_pool_implementations(uint256 _implementation_index, address _implementation) external;

    /**
     * @notice Set implementation contracts for metapools
     * @dev Only callable by admin
     * @param _implementation_index Implementation index where implementation is stored
     * @param _implementation Implementation address to use when deploying meta pools
     */
    function set_metapool_implementations(uint256 _implementation_index, address _implementation) external;

    /**
     * @notice Set implementation contracts for StableSwap Math
     * @dev Only callable by admin
     * @param _math_implementation Address of the math implementation contract
     */
    function set_math_implementation(address _math_implementation) external;

    /**
     * @notice Set implementation contracts for liquidity gauge
     * @dev Only callable by admin
     * @param _gauge_implementation Address of the gauge blueprint implementation contract
     */
    function set_gauge_implementation(address _gauge_implementation) external;

    /**
     * @notice Set implementation contracts for Views methods
     * @dev Only callable by admin
     * @param _views_implementation Implementation address of views contract
     */
    function set_views_implementation(address _views_implementation) external;
}

File 35 of 36 : ICurveStableSwapNG.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

// from https://github.com/curvefi/stableswap-ng

/**
 * @title ICurveStableSwapNG
 * @notice Interface for the curve stable swap pool.
 */
interface ICurveStableSwapNG {
    /**
     * @notice Calculate the current input dx given output dy
     * @dev Index values can be found via the `coins` public getter method
     * @param i Index value for the coin to send
     * @param j Index value of the coin to receive
     * @param dy Amount of `j` being received after exchange
     * @param pool Address of the pool
     * @return Amount of `i` predicted
     */
    function get_dx(int128 i, int128 j, uint256 dy, address pool) external view returns (uint256);

    /**
     * @notice Calculate the current output dy given input dx
     * @dev Index values can be found via the `coins` public getter method
     * @param i Index value for the coin to send
     * @param j Index value of the coin to receive
     * @param dx Amount of `i` being exchanged
     * @return Amount of `j` predicted
     */
    function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);

    /**
     * @notice Calculate the amount received when withdrawing a single coin
     * @param _burn_amount Amount of LP tokens to burn in the withdrawal
     * @param i Index value of the coin to withdraw
     * @return Amount of coin received
     */
    function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);

    /**
     * @notice Returns the address of the token at the specified index.
     * @param i The index of the token.
     * @return The address of the token at the specified index.
     */
    function coins(uint256 i) external view returns (address);

    /**
     * @notice Returns the number of underlying coins in the pool.
     * @return The number of underlying coins in the pool.
     */
    function N_COINS() external view returns (uint256);

    /**
     * @notice Perform an exchange between two coins
     * @dev Index values can be found via the `coins` public getter method
     * @param i Index value for the coin to send
     * @param j Index value of the coin to receive
     * @param _dx Amount of `i` being exchanged
     * @param _min_dy Minimum amount of `j` to receive
     * @return Actual amount of `j` received
     */
    function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external returns (uint256);

    /**
     * @notice Deposit coins into the pool
     * @param _amounts List of amounts of coins to deposit
     * @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit
     * @return Amount of LP tokens received by depositing
     */
    function add_liquidity(uint256[] memory _amounts, uint256 _min_mint_amount) external returns (uint256);

    /**
     * @notice Withdraw a single coin from the pool
     * @param _burn_amount Amount of LP tokens to burn in the withdrawal
     * @param i Index value of the coin to withdraw
     * @param _min_received Minimum amount of coin to receive
     * @return Amount of coin received
     */
    function remove_liquidity_one_coin(uint256 _burn_amount, int128 i, uint256 _min_received) external returns (uint256);

    /**
     * @notice Withdraw coins from the pool in an imbalanced amount
     * @param _amounts List of amounts of underlying coins to withdraw
     * @param _max_burn_amount Maximum amount of LP token to burn in the withdrawal
     * @return Actual amount of the LP token burned in the withdrawal
     */
    function remove_liquidity_imbalance(uint256[] memory _amounts, uint256 _max_burn_amount) external returns (uint256);

    /**
     * @notice Withdraw coins from the pool
     * @dev Withdrawal amounts are based on current deposit ratios
     * @param _burn_amount Quantity of LP tokens to burn in the withdrawal
     * @param _min_amounts Minimum amounts of underlying coins to receive
     * @param _receiver Address that receives the withdrawn coins
     * @param _claim_admin_fees Whether to claim admin fees
     * @return List of amounts of coins that were withdrawn
     */
    function remove_liquidity(uint256 _burn_amount, uint256[] memory _min_amounts, address _receiver, bool _claim_admin_fees)
        external
        returns (uint256[] memory);
}

File 36 of 36 : Error.sol
//       c=<
//        |
//        |   ////\    1@2
//    @@  |  /___\**   @@@2			@@@@@@@@@@@@@@@@@@@@@@
//   @@@  |  |~L~ |*   @@@@@@		@@@  @@@@@        @@@@    @@@ @@@@    @@@  @@@@@@@@ @@@@ @@@@    @@@ @@@@@@@@@ @@@@   @@@@
//  @@@@@ |   \=_/8    @@@@1@@		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@   @@@ @@@@@@@@@ @@@@ @@@@@  @@@@ @@@@@@@@@  @@@@ @@@@
// @@@@@@| _ /| |\__ @@@@@@@@2		@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@ @@@ @@@@      @@@@ @@@@@@ @@@@ @@@         @@@@@@@
// 1@@@@@@|\  \___/)   @@1@@@@@2	~~~  ~~~~~  @@@@  ~~@@    ~~~ ~~~~~~~~~~~ ~~~~      ~~~~ ~~~~~~~~~~~ ~@@          @@@@@
// 2@@@@@ |  \ \ / |     @@@@@@2	@@@  @@@@@  @@@@  @@@@    @@@ @@@@@@@@@@@ @@@@@@@@@ @@@@ @@@@@@@@@@@ @@@@@@@@@    @@@@@
// 2@@@@  |_  >   <|__    @@1@12	@@@  @@@@@  @@@@  @@@@    @@@ @@@@ @@@@@@ @@@@      @@@@ @@@@ @@@@@@ @@@         @@@@@@@
// @@@@  / _|  / \/    \   @@1@		@@@   @@@   @@@@  @@@@    @@@ @@@@  @@@@@ @@@@      @@@@ @@@@  @@@@@ @@@@@@@@@  @@@@ @@@@
//  @@ /  |^\/   |      |   @@1		@@@         @@@@  @@@@    @@@ @@@@    @@@ @@@@      @@@@ @@@    @@@@ @@@@@@@@@ @@@@   @@@@
//   /     / ---- \ \\\=    @@		@@@@@@@@@@@@@@@@@@@@@@
//   \___/ --------  ~~    @@@
//     @@  | |   | |  --   @@
// ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

library Error {
    /*///////////////////////////////////////////////////////////////
                                            GENERIC
    ///////////////////////////////////////////////////////////////*/

    error AlreadyExists();

    error DoesNotExist();

    error Unauthorized();

    error InvalidLength();

    error NotOwner();

    error InvalidWormholeChainId();

    error InvalidCallerContext();

    /*///////////////////////////////////////////////////////////////
                                            ADDRESS
    ///////////////////////////////////////////////////////////////*/

    error ImplementationMismatch(address implementation, address latestImplementation);

    error InvalidWithdrawalAddress(address to);

    error NullAddress();

    error SameAddress();

    error InvalidSolanaAddress();

    error AddressAlreadySet();

    error InsufficientAllowlistDelay();

    /*///////////////////////////////////////////////////////////////
                                    AMOUNT / BALANCE
    ///////////////////////////////////////////////////////////////*/

    error InsufficientBalance();

    error InsufficientWithdrawalAmount(uint256 amount);

    error InsufficientBalanceForFee(uint256 balance, uint256 fee);

    error InvalidNonce(bytes32 nonce);

    error ZeroValue();

    error AmountDeltaZeroValue();

    error DecimalsMoreThan18(uint256 decimals);

    error InsufficientBridgeAmount();

    error BridgeMaxAmountExceeded();

    error ETHTransferFailed();

    error OutOfBounds();

    /*///////////////////////////////////////////////////////////////
                                            ACCOUNT
    ///////////////////////////////////////////////////////////////*/

    error CreateAccountDisabled();

    error InvalidKeysForSalt();

    error PredictAddressDisabled();

    error FundsRecoveryActivationDeadlinePending();

    error InvalidAppAccount();

    error InvalidAppBeacon();

    /*///////////////////////////////////////////////////////////////
                                        KEY MANAGEMENT
    ///////////////////////////////////////////////////////////////*/

    error InvalidRequest();

    error InvalidKeySignature(address from);

    error KeyAlreadyInvalid();

    error KeyAlreadyValid();

    error KeyNotFound();

    error CannotRemoveLastKey();

    /*///////////////////////////////////////////////////////////////
                                     GAS FEE REBATE
    ///////////////////////////////////////////////////////////////*/

    error InvalidDeductGasFunction(bytes4 sig);

    /*///////////////////////////////////////////////////////////////
                                FEATURE FLAGS
    ///////////////////////////////////////////////////////////////*/

    error FundsRecoveryNotActive();
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@pythnetwork/entropy-sdk-solidity/=node_modules/@pythnetwork/entropy-sdk-solidity/",
    "@synthetixio/core-contracts/=node_modules/@synthetixio/core-contracts/",
    "@synthetixio/core-modules/=node_modules/@synthetixio/core-modules/",
    "@synthetixio/main/=node_modules/@synthetixio/main/",
    "@synthetixio/oracle-manager/=node_modules/@synthetixio/oracle-manager/",
    "@synthetixio/perps-market/=node_modules/@synthetixio/perps-market/",
    "@synthetixio/spot-market/=node_modules/@synthetixio/spot-market/",
    "cannon-std/=lib/cannon-std/src/",
    "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/",
    "src/=src/",
    "test/=test/",
    "wormhole-circle-integration/=lib/wormhole-circle-integration/evm/src/",
    "wormhole/=lib/wormhole-circle-integration/evm/src/"
  ],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ImplementationIsSterile","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"address","name":"latestImplementation","type":"address"}],"name":"ImplementationMismatch","type":"error"},{"inputs":[],"name":"InvalidAppBeacon","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"InvalidKeySignature","type":"error"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"InvalidPoolAddress","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"NoChange","type":"error"},{"inputs":[{"internalType":"address","name":"contr","type":"address"}],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NullAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenIndexMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"UnsupportedPool","type":"error"},{"inputs":[],"name":"UpgradeSimulationFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"appBeacon","type":"address"}],"name":"AppBeaconSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC1155BatchRecoveredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC1155BatchTransferredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ERC1155RecoveredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ERC1155TransferredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20RecoveredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TransferredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721RecoveredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721TransferredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherRecoveredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherTransferredToMainAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stableSwapPool","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"lpAmount","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stableSwapPool","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"lpAmount","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stableSwapPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountRemoved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpAmountBurnt","type":"uint256"}],"name":"LiquidityRemovedSingleToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"mainAccount","type":"address"}],"name":"MainAccountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stableSwapPool","type":"address"},{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"TokensExchanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"self","type":"address"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[{"internalType":"address","name":"_stableSwapPool","type":"address"},{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256","name":"_minLPAmount","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"appVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_stableSwapPool","type":"address"},{"internalType":"address","name":"_fromToken","type":"address"},{"internalType":"address","name":"_toToken","type":"address"},{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"uint256","name":"_minToAmount","type":"uint256"}],"name":"exchange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAppBeacon","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMainAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_mainAccount","type":"address"},{"internalType":"address","name":"_appBeacon","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"recoverERC1155BatchToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"recoverERC1155ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_LPToken","type":"address"},{"internalType":"int128","name":"_tokenIndex","type":"int128"},{"internalType":"uint256","name":"_minToAmount","type":"uint256"}],"name":"recoverERC20FromLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverERC20ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stableSwapPool","type":"address"},{"internalType":"address","name":"_fromToken","type":"address"},{"internalType":"uint256","name":"_minToAmount","type":"uint256"}],"name":"recoverERC20ToUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"recoverERC721ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEtherToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_LPToken","type":"address"},{"internalType":"int128","name":"_USDCIndex","type":"int128"},{"internalType":"uint256","name":"_minReceiveAmount","type":"uint256"}],"name":"recoverUSDCFromLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stableSwapPool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"removeLiquidityImbalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stableSwapPool","type":"address"},{"internalType":"int128","name":"_tokenIndex","type":"int128"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"uint256","name":"_minReceiveAmount","type":"uint256"}],"name":"removeSingleTokenLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"simulateUpgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferERC1155BatchToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferERC1155ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferERC721ToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferEtherToMainAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_appBeacon","type":"address"},{"internalType":"address","name":"_latestAppImplementation","type":"address"}],"name":"upgradeAppVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106101c65760003560e01c8063768c566f116100f7578063bc197c8111610095578063c99fa37211610064578063c99fa3721461052f578063dae0cda21461054f578063dc122e4614610564578063f23a6e611461058457600080fd5b8063bc197c81146104ae578063c6c15c9e146104da578063c7f62cda146104ef578063c8d35f221461050f57600080fd5b8063953e8251116100d1578063953e82511461043d578063a89886eb1461045d578063aaf10f421461047d578063b148b0fd1461049257600080fd5b8063768c566f146103dd57806388555ddf146103fd5780638944240c1461041d57600080fd5b80633659cfe6116101645780634798ce5b1161013e5780634798ce5b1461035d578063485cc9551461037d578063516792a11461039d57806369f65120146103bd57600080fd5b80633659cfe6146102fd578063393d0c0f1461031d578063425061391461033d57600080fd5b80630ca7ff3b116101a05780630ca7ff3b14610249578063150b7a021461027657806329c57543146102af57806331ca6c99146102cf57600080fd5b806301ffc9a7146101d2578063032f261314610207578063094a96341461022957600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed366004612a4e565b6105b0565b60405190151581526020015b60405180910390f35b34801561021357600080fd5b50610227610222366004612a9c565b6105db565b005b34801561023557600080fd5b50610227610244366004612add565b610886565b34801561025557600080fd5b5061025e610c9a565b6040516001600160a01b0390911681526020016101fe565b34801561028257600080fd5b50610296610291366004612bc2565b610ca9565b6040516001600160e01b031990911681526020016101fe565b3480156102bb57600080fd5b506102276102ca366004612cb9565b610cba565b3480156102db57600080fd5b506102ef6102ea366004612d65565b610cfe565b6040519081526020016101fe565b34801561030957600080fd5b50610227610318366004612dab565b610d35565b34801561032957600080fd5b50610227610338366004612dab565b610d62565b34801561034957600080fd5b50610227610358366004612dc8565b610e44565b34801561036957600080fd5b50610227610378366004612df4565b610e79565b34801561038957600080fd5b50610227610398366004612e4f565b6110f7565b3480156103a957600080fd5b506102276103b8366004612dc8565b61129a565b3480156103c957600080fd5b506102276103d8366004612e4f565b6112c3565b3480156103e957600080fd5b506102276103f8366004612dc8565b61136f565b34801561040957600080fd5b50610227610418366004612e88565b6113db565b34801561042957600080fd5b50610227610438366004612cb9565b611414565b34801561044957600080fd5b50610227610458366004612ee3565b61148d565b34801561046957600080fd5b50610227610478366004612f4c565b6114c1565b34801561048957600080fd5b5061025e6115af565b34801561049e57600080fd5b50604051600181526020016101fe565b3480156104ba57600080fd5b506102966104c9366004613029565b63bc197c8160e01b95945050505050565b3480156104e657600080fd5b5061025e6115c8565b3480156104fb57600080fd5b5061022761050a366004612dab565b6115d2565b34801561051b57600080fd5b5061022761052a3660046130d6565b6116e7565b34801561053b57600080fd5b5061022761054a366004612a9c565b611a0b565b34801561055b57600080fd5b50610227611aad565b34801561057057600080fd5b5061022761057f366004613160565b611b12565b34801561059057600080fd5b5061029661059f366004613179565b63f23a6e6160e01b95945050505050565b60006001600160e01b03198216632775e53160e21b14806105d557506105d582611b42565b92915050565b6105e3611b77565b6105f36105ee611bc1565b611c13565b610629576105ff611bc1565b6040516357a92af760e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b60006106336115c8565b90506000816001600160a01b03166389a302716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610675573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069991906131e1565b60405163c661065760e01b81526fffffffffffffffffffffffffffffffff861660048201529091506001600160a01b03808316919087169063c661065790602401602060405180830381865afa1580156106f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071b91906131e1565b6001600160a01b03161461074257604051630204827360e41b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa158015610789573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ad91906131fe565b905060006107bd87878488611c8a565b9050826001600160a01b03167f1490eda4bca13d77e383d3a56965041039bd157c686d0fae8b12a80182622b0b826040516107fa91815260200190565b60405180910390a26040516370a0823160e01b81523060048201526108759084906001600160a01b038216906370a0823190602401602060405180830381865afa15801561084c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087091906131fe565b611d60565b50505050610881611db5565b505050565b61088e611b77565b6108996105ee611bc1565b6108a5576105ff611bc1565b6108ae83611ddb565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156108f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091991906131fe565b905060006109256115c8565b90506000816001600160a01b03166389a302716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098b91906131e1565b90506000806109986115c8565b6001600160a01b031663cd80c2976040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f991906131e1565b60405163eb85226d60e01b81526001600160a01b038a8116600483015289811660248301528581166044830152919091169063eb85226d90606401606060405180830381865afa158015610a51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a75919061322c565b5060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018990529294509092509088169063095ea7b3906044016020604051808303816000875af1158015610acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af09190613274565b50604051630f7c084960e21b8152600f83810b600483015282900b602482015260448101869052606481018790526000906001600160a01b038a1690633df02124906084016020604051808303816000875af1158015610b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7891906131fe565b604080516001600160a01b038b811682528781166020830152918101899052606081018390529192508a16907fe065ccf331737789c42691e445bb680198682dadf51e4de1f877c48ef40a54e59060800160405180910390a26040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c91906131fe565b9050846001600160a01b03167f1490eda4bca13d77e383d3a56965041039bd157c686d0fae8b12a80182622b0b82604051610c7991815260200190565b60405180910390a2610c8b8582611d60565b50505050505050610881611db5565b6000610ca4611f86565b905090565b630a85bd0160e11b5b949350505050565b610cc2611b77565b610cd2610ccd611bc1565b611fa1565b610cde576105ff611bc1565b610ced87878787878787611fdb565b610cf5611db5565b50505050505050565b6000610d08611b77565b610d13610ccd611bc1565b610d1f576105ff611bc1565b610d2b85858585611c8a565b9050610cb2611db5565b610d3d6120a2565b54600160a01b900460ff1615610d5957610d568161210e565b50565b610d5681612234565b610d6a611b77565b610d756105ee611bc1565b610d81576105ff611bc1565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dec91906131fe565b9050816001600160a01b03167f1490eda4bca13d77e383d3a56965041039bd157c686d0fae8b12a80182622b0b82604051610e2991815260200190565b60405180910390a2610e3b8282611d60565b50610d56611db5565b610e4c611b77565b610e57610ccd611bc1565b610e63576105ff611bc1565b610e6d8282612278565b610e75611db5565b5050565b610e81611b77565b610e8c610ccd611bc1565b610e98576105ff611bc1565b610ea185611ddb565b600080610eac6115c8565b6001600160a01b031663cd80c2976040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0d91906131e1565b60405163eb85226d60e01b81526001600160a01b03898116600483015288811660248301528781166044830152919091169063eb85226d90606401606060405180830381865afa158015610f65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f89919061322c565b5060405163095ea7b360e01b81526001600160a01b038a81166004830152602482018890529294509092509087169063095ea7b3906044016020604051808303816000875af1158015610fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110049190613274565b50604051630f7c084960e21b8152600f83810b600483015282900b602482015260448101859052606481018490526000906001600160a01b03891690633df02124906084016020604051808303816000875af1158015611068573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108c91906131fe565b604080516001600160a01b038a811682528981166020830152918101889052606081018390529192508916907fe065ccf331737789c42691e445bb680198682dadf51e4de1f877c48ef40a54e59060800160405180910390a25050506110f0611db5565b5050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561113c5750825b90506000826001600160401b031660011480156111585750303b155b905081158015611166575080155b156111845760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156111ae57845460ff60401b1916600160401b1785555b6111b787612336565b6040516301ffc9a760e01b815263bba49abf60e01b60048201526001600160a01b038716906301ffc9a790602401602060405180830381865afa158015611202573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112269190613274565b6112435760405163a9572d4760e01b815260040160405180910390fd5b61124c866123c5565b8315610cf557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a150505050505050565b6112a2611b77565b6112ad610ccd611bc1565b6112b9576105ff611bc1565b610e6d8282611d60565b6112cb612457565b6001600160a01b0316826001600160a01b0316146112ec576112ec82612475565b306001600160a01b031663aaf10f426040518163ffffffff1660e01b8152600401602060405180830381865afa15801561132a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134e91906131e1565b6001600160a01b0316816001600160a01b031614610e7557610e7581610d35565b61137a6105ee611bc1565b611386576105ff611bc1565b61138e611b77565b816001600160a01b03167f58ee56325c801734ee24ce264bb5f47387699b94893ea40b900fecb5ac23c2cb826040516113c991815260200190565b60405180910390a2610e6d8282612278565b6113e3611b77565b6113ee610ccd611bc1565b6113fa576105ff611bc1565b611406848484846124b9565b61140e611db5565b50505050565b61141f6105ee611bc1565b61142b576105ff611bc1565b611433611b77565b866001600160a01b03167fec25107be6169b43e1cc4bdca3d2852625b29a170aac79633b642cb21357b7a1878787878787604051611476969594939291906132ea565b60405180910390a2610ced87878787878787611fdb565b611495611b77565b6114a0610ccd611bc1565b6114ac576105ff611bc1565b6114b98585858585612586565b6110f0611db5565b6114cc6105ee611bc1565b6114d8576105ff611bc1565b6114e0611b77565b604051627eeac760e11b8152306004820152602481018490526000906001600160a01b0386169062fdd58e90604401602060405180830381865afa15801561152c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155091906131fe565b9050846001600160a01b03167fe3c41e05bfdb3e6db681c69d719317d429ebbe97426bea2f3c2b58de1d4dd5eb858386866040516115919493929190613333565b60405180910390a26115a68585838686612586565b5061140e611db5565b60006115b96120a2565b546001600160a01b0316919050565b6000610ca4612457565b60006115dc6120a2565b80546001600160a01b038481166001600160a81b031983168117600160a01b1784556040805192909316602480840182905284518085039091018152604490930184526020830180516001600160e01b0316631b2ce7f360e11b179052925193945091926000929161164d91613353565b600060405180830381855af49150503d8060008114611688576040519150601f19603f3d011682016040523d82523d6000602084013e61168d565b606091505b505090508015806116b85750816001600160a01b03166116ab6120a2565b546001600160a01b031614155b156116d657604051631439f4b560e31b815260040160405180910390fd5b825460ff60a01b1916835560008080fd5b6116ef611b77565b6116fa610ccd611bc1565b611706576105ff611bc1565b61170f86611ddb565b60006117196115c8565b6001600160a01b031663cd80c2976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177a91906131e1565b604051639ac90d3d60e01b81526001600160a01b0389811660048301529190911690639ac90d3d90602401600060405180830381865afa1580156117c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117ea9190810190613382565b905060005b8581101561193b578686828181106118095761180961341b565b905060200201602081019061181e9190612dab565b6001600160a01b03168282815181106118395761183961341b565b60200260200101516001600160a01b0316146118685760405163c1ab6dc160e01b815260040160405180910390fd5b86868281811061187a5761187a61341b565b905060200201602081019061188f9190612dab565b6001600160a01b031663095ea7b3898787858181106118b0576118b061341b565b6040516001600160e01b031960e087901b1681526001600160a01b03909416600485015260200291909101356024830152506044016020604051808303816000875af1158015611904573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119289190613274565b508061193381613447565b9150506117ef565b50604051635b96faef60e11b81526000906001600160a01b0389169063b72df5de9061196f90889088908890600401613460565b6020604051808303816000875af115801561198e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b291906131fe565b9050876001600160a01b03167fb60e972ce1258a7280a8e34204b1df88fcabbe8aea805e46bc1566cdc6e6e1488686846040516119f193929190613460565b60405180910390a25050611a03611db5565b505050505050565b611a13611b77565b611a1e6105ee611bc1565b611a2a576105ff611bc1565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015611a71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9591906131fe565b9050611aa384848385611c8a565b5050610881611db5565b611ab86105ee611bc1565b611ac4576105ff611bc1565b611acc611b77565b6040514781527f3702b0a28fa1c0efd493c067137b6b6d49557fef71c5fbbdd35069e71ba942479060200160405180910390a1611b0847612643565b611b10611db5565b565b611b1a611b77565b611b25610ccd611bc1565b611b31576105ff611bc1565b611b3a81612643565b610d56611db5565b60006001600160e01b03198216630271189760e51b14806105d557506301ffc9a760e01b6001600160e01b03198316146105d5565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611bbb57604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6000366014611bcf336126f1565b8015611bdb5750808210155b15611c0b57600036611bed8385613484565b611bf8928290613497565b611c01916134c1565b60601c9250505090565b339250505090565b6000611c1d611f86565b60405163302dce5360e21b81526001600160a01b038481166004830152919091169063c0b7394c906024015b602060405180830381865afa158015611c66573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190613274565b6000611c9585611ddb565b604051630d2680e960e11b815260048101849052600f85900b6024820152604481018390526001600160a01b03861690631a4d01d2906064016020604051808303816000875af1158015611ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1191906131fe565b60408051828152602081018690529192506001600160a01b038716917f23d1e1a4d513807e3fbaf3e6c477ad26d11e91ff022afdf904e1e4a9b9b5cba7910160405180910390a2949350505050565b816001600160a01b03167fb6b6eaf67b6207ffe0dfadabc3d2dca6091f9769ccf06db1cf7c911a6f71d6e782604051611d9b91815260200190565b60405180910390a2610e7582611daf611f86565b8361272b565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6000611de56115c8565b604051637615a71b60e11b81526001600160a01b0384811660048301529192509082169063ec2b4e3690602401602060405180830381865afa158015611e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e539190613274565b611e7b57604051630e13b6ff60e11b81526001600160a01b0383166004820152602401610620565b60006001600160a01b0316816001600160a01b031663cd80c2976040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee891906131e1565b604051631443662960e21b81526001600160a01b038581166004830152919091169063510d98a490602401602060405180830381865afa158015611f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5491906131e1565b6001600160a01b031603610e7557604051632fdbd21560e21b81526001600160a01b0383166004820152602401610620565b600080611f9161277d565b546001600160a01b031692915050565b6000611fab611f86565b60405163f462ccf560e01b81526001600160a01b038481166004830152919091169063f462ccf590602401611c49565b866001600160a01b03167f18d5f63b7c63b78d33d0d94e1309505ade1d2bb8b48ba4d99f0f22cb67c4123187878787878760405161201e969594939291906132ea565b60405180910390a2866001600160a01b0316632eb2c2d63061203e611f86565b8989898989896040518963ffffffff1660e01b81526004016120679897969594939291906134f6565b600060405180830381600087803b15801561208157600080fd5b505af1158015612095573d6000803e3d6000fd5b5050505050505050505050565b6000806040516020016120f09060208082526021908201527f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f786040820152607960f81b606082015260800190565b60408051601f19818403018152919052805160209091012092915050565b6001600160a01b0381166121355760405163d92e233d60e01b815260040160405180910390fd5b803b61215f576040516322a2d07b60e21b81526001600160a01b0382166004820152602401610620565b60006121696120a2565b80549091506001600160a01b039081169083160361219a5760405163a88ee57760e01b815260040160405180910390fd5b8054600160a01b900460ff161580156121b757506121b7826127b6565b156121e057604051631550430160e01b81526001600160a01b0383166004820152602401610620565b80546001600160a01b0319166001600160a01b038316908117825560405190815230907f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c79060200160405180910390a25050565b61223c611f86565b6001600160a01b0316336001600160a01b03161461226f576040516357a92af760e01b8152336004820152602401610620565b610d568161210e565b816001600160a01b03167f753e7bd83208768248a0a06a9eccd66e93c9b4efac423cb4f0f1ea574543364a826040516122b391815260200190565b60405180910390a2816001600160a01b03166342842e0e306122d3611f86565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101849052606401600060405180830381600087803b15801561232257600080fd5b505af1158015611a03573d6000803e3d6000fd5b600061234061277d565b90506001600160a01b0382166123695760405163e99d5ac560e01b815260040160405180910390fd5b6040516001600160a01b03831681527fbb3095240b0ff40d4397794f83b7f37cd4ace7b39a3f76ccb481451d4c8495539060200160405180910390a180546001600160a01b0319166001600160a01b0392909216919091179055565b60006123cf61277d565b90506001600160a01b0382166123f85760405163e99d5ac560e01b815260040160405180910390fd5b6040516001600160a01b03831681527fd4f9fe99f46b3df1b88f6aec2cda52ba754ee73897c1e1f08151709e51aef9f59060200160405180910390a160010180546001600160a01b0319166001600160a01b0392909216919091179055565b60008061246261277d565b600101546001600160a01b031692915050565b61247d611f86565b6001600160a01b0316336001600160a01b0316146124b0576040516357a92af760e01b8152336004820152602401610620565b610d56816123c5565b6124c284611ddb565b604051637706db7560e01b81526000906001600160a01b03861690637706db75906124f590869086908990600401613460565b6020604051808303816000875af1158015612514573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253891906131fe565b9050846001600160a01b03167f0f74fe264fb7d04b4800409b8a3562eb271296e19c3ec8835639635b3e858c4584848460405161257793929190613460565b60405180910390a25050505050565b846001600160a01b03167f5260ae85d5df34566835d84b52f95acc3a4ad5f63aebd09a9a2b91b6d06593f2858585856040516125c59493929190613333565b60405180910390a2846001600160a01b031663f242432a306125e5611f86565b878787876040518763ffffffff1660e01b815260040161260a9695949392919061355a565b600060405180830381600087803b15801561262457600080fd5b505af1158015612638573d6000803e3d6000fd5b505050505050505050565b6040518181527fd27705288cc1cd8ecc51257763f25533f3143be0026c3c6935f1558237346fb09060200160405180910390a16000612680611f86565b6001600160a01b03168260405160006040518083038185875af1925050503d80600081146126ca576040519150601f19603f3d011682016040523d82523d6000602084013e6126cf565b606091505b5050905080610e755760405163b12d13eb60e01b815260040160405180910390fd5b60006126fb611f86565b60405163572b6c0560e01b81526001600160a01b038481166004830152919091169063572b6c0590602401611c49565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526108819084906128b4565b6000806040516020016120f090602080825260129082015271696f2e696e66696e65782e4170704261736560701b604082015260600190565b604080516001600160a01b03831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166363fb166d60e11b179052905160009182918291309161280d9190613353565b600060405180830381855af49150503d8060008114612848576040519150601f19603f3d011682016040523d82523d6000602084013e61284d565b606091505b509150915081158015610cb25750604051631439f4b560e31b602082015260240160405160208183030381529060405280519060200120816040516020016128959190613353565b6040516020818303038152906040528051906020012014949350505050565b60006128c96001600160a01b03841683612917565b905080516000141580156128ee5750808060200190518101906128ec9190613274565b155b1561088157604051635274afe760e01b81526001600160a01b0384166004820152602401610620565b60606129258383600061292c565b9392505050565b6060814710156129515760405163cd78605960e01b8152306004820152602401610620565b600080856001600160a01b0316848660405161296d9190613353565b60006040518083038185875af1925050503d80600081146129aa576040519150601f19603f3d011682016040523d82523d6000602084013e6129af565b606091505b50915091506129bf8683836129c9565b9695505050505050565b6060826129de576129d982612a25565b612925565b81511580156129f557506001600160a01b0384163b155b15612a1e57604051639996b31560e01b81526001600160a01b0385166004820152602401610620565b5080612925565b805115612a355780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215612a6057600080fd5b81356001600160e01b03198116811461292557600080fd5b6001600160a01b0381168114610d5657600080fd5b80600f0b8114610d5657600080fd5b600080600060608486031215612ab157600080fd5b8335612abc81612a78565b92506020840135612acc81612a8d565b929592945050506040919091013590565b600080600060608486031215612af257600080fd5b8335612afd81612a78565b92506020840135612acc81612a78565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612b4b57612b4b612b0d565b604052919050565b600082601f830112612b6457600080fd5b81356001600160401b03811115612b7d57612b7d612b0d565b612b90601f8201601f1916602001612b23565b818152846020838601011115612ba557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215612bd857600080fd5b8435612be381612a78565b93506020850135612bf381612a78565b92506040850135915060608501356001600160401b03811115612c1557600080fd5b612c2187828801612b53565b91505092959194509250565b60008083601f840112612c3f57600080fd5b5081356001600160401b03811115612c5657600080fd5b6020830191508360208260051b8501011115612c7157600080fd5b9250929050565b60008083601f840112612c8a57600080fd5b5081356001600160401b03811115612ca157600080fd5b602083019150836020828501011115612c7157600080fd5b60008060008060008060006080888a031215612cd457600080fd5b8735612cdf81612a78565b965060208801356001600160401b0380821115612cfb57600080fd5b612d078b838c01612c2d565b909850965060408a0135915080821115612d2057600080fd5b612d2c8b838c01612c2d565b909650945060608a0135915080821115612d4557600080fd5b50612d528a828b01612c78565b989b979a50959850939692959293505050565b60008060008060808587031215612d7b57600080fd5b8435612d8681612a78565b93506020850135612d9681612a8d565b93969395505050506040820135916060013590565b600060208284031215612dbd57600080fd5b813561292581612a78565b60008060408385031215612ddb57600080fd5b8235612de681612a78565b946020939093013593505050565b600080600080600060a08688031215612e0c57600080fd5b8535612e1781612a78565b94506020860135612e2781612a78565b93506040860135612e3781612a78565b94979396509394606081013594506080013592915050565b60008060408385031215612e6257600080fd5b8235612e6d81612a78565b91506020830135612e7d81612a78565b809150509250929050565b60008060008060608587031215612e9e57600080fd5b8435612ea981612a78565b93506020850135925060408501356001600160401b03811115612ecb57600080fd5b612ed787828801612c2d565b95989497509550505050565b600080600080600060808688031215612efb57600080fd5b8535612f0681612a78565b9450602086013593506040860135925060608601356001600160401b03811115612f2f57600080fd5b612f3b88828901612c78565b969995985093965092949392505050565b60008060008060608587031215612f6257600080fd5b8435612f6d81612a78565b93506020850135925060408501356001600160401b03811115612f8f57600080fd5b612ed787828801612c78565b60006001600160401b03821115612fb457612fb4612b0d565b5060051b60200190565b600082601f830112612fcf57600080fd5b81356020612fe4612fdf83612f9b565b612b23565b82815260059290921b8401810191818101908684111561300357600080fd5b8286015b8481101561301e5780358352918301918301613007565b509695505050505050565b600080600080600060a0868803121561304157600080fd5b853561304c81612a78565b9450602086013561305c81612a78565b935060408601356001600160401b038082111561307857600080fd5b61308489838a01612fbe565b9450606088013591508082111561309a57600080fd5b6130a689838a01612fbe565b935060808801359150808211156130bc57600080fd5b506130c988828901612b53565b9150509295509295909350565b600080600080600080608087890312156130ef57600080fd5b86356130fa81612a78565b955060208701356001600160401b038082111561311657600080fd5b6131228a838b01612c2d565b9097509550604089013591508082111561313b57600080fd5b5061314889828a01612c2d565b979a9699509497949695606090950135949350505050565b60006020828403121561317257600080fd5b5035919050565b600080600080600060a0868803121561319157600080fd5b853561319c81612a78565b945060208601356131ac81612a78565b9350604086013592506060860135915060808601356001600160401b038111156131d557600080fd5b6130c988828901612b53565b6000602082840312156131f357600080fd5b815161292581612a78565b60006020828403121561321057600080fd5b5051919050565b8051801515811461322757600080fd5b919050565b60008060006060848603121561324157600080fd5b835161324c81612a8d565b602085015190935061325d81612a8d565b915061326b60408501613217565b90509250925092565b60006020828403121561328657600080fd5b61292582613217565b81835260006001600160fb1b038311156132a857600080fd5b8260051b80836020870137939093016020019392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6060815260006132fe60608301888a61328f565b828103602084015261331181878961328f565b905082810360408401526133268185876132c1565b9998505050505050505050565b8481528360208201526060604082015260006129bf6060830184866132c1565b6000825160005b81811015613374576020818601810151858301520161335a565b506000920191825250919050565b6000602080838503121561339557600080fd5b82516001600160401b038111156133ab57600080fd5b8301601f810185136133bc57600080fd5b80516133ca612fdf82612f9b565b81815260059190911b820183019083810190878311156133e957600080fd5b928401925b8284101561341057835161340181612a78565b825292840192908401906133ee565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161345957613459613431565b5060010190565b60408152600061347460408301858761328f565b9050826020830152949350505050565b818103818111156105d5576105d5613431565b600080858511156134a757600080fd5b838611156134b457600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff1981358181169160148510156134ee5780818660140360031b1b83161692505b505092915050565b6001600160a01b0389811682528816602082015260a060408201819052600090613523908301888a61328f565b828103606084015261353681878961328f565b9050828103608084015261354b8185876132c1565b9b9a5050505050505050505050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905260009061359590830184866132c1565b9897505050505050505056fea264697066735822122048026625e2ae6f658f6f711421624f1e1c1314c4d62ae956b3cc5f011214bda364736f6c63430008150033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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.