creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "CurveHandler.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"SafeERC20.sol\";\nimport \"IERC20.sol\";\n\nimport \"ILpToken.sol\";\nimport \"ICurveHandler.sol\";\nimport \"ICurveRegistryCache.sol\";\nimport \"IWETH.sol\";\nimport \"ICurvePoolV1.sol\";\nimport \"ICurvePoolV0.sol\";\nimport \"ICurvePoolV2.sol\";\nimport \"ICurvePoolV7.sol\";\nimport \"ICurvePoolV1Eth.sol\";\nimport \"ICurvePoolV2Eth.sol\";\nimport \"IController.sol\";\n\nimport \"StringUtils.sol\";\n\n/// @notice This contract acts as a wrapper for depositing and removing liquidity to and from Curve pools.\n/// Please be aware of the following:\n/// - This contract accepts WETH and unwraps it for Curve pool deposits\n/// - This contract should only be used through delegate calls for deposits and withdrawals\n/// - Slippage from deposits and withdrawals is handled in the ConicPool (do not use handler elsewhere)\ncontract CurveHandler is ICurveHandler {\n    using SafeERC20 for IERC20;\n\n    address internal constant _ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n    IWETH internal constant _WETH = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n\n    // Normal calls to `exchange` functions will read various state variables, resulting in\n    // gas fees that are always in the double-digit thousand gas.\n    // On the other hand, a reentrant call will only read a single warm variable (100 gas)\n    // and call a contract already touched, so it will use vastly less than 5k gas.\n    // In practice, reentrant calls appear to use ~1.5k gas while non-reentrant\n    // calls use ~60k gas.\n    // We are better off setting this value a little too high compared to the ~1.5k estimate\n    // to make sure that we always prevent reentrant calls.\n    uint256 internal constant LOCK_GAS_THRESHOLD = 5_000;\n\n    // Recent factory pools are deployed using a minimal proxy pattern pointing to\n    // 1. `0x847ee1227a9900b73aeeb3a47fac92c52fd54ed9`\n    // 2. `0x94b4dfd9ba5865cc931195c99a2db42f3fc5d45b`\n    // The exact bytecodes are:\n    // 1. `0x363d3d373d3d3d363d73847ee1227a9900b73aeeb3a47fac92c52fd54ed95af43d82803e903d91602b57fd5bf3`\n    // 2. `0x363d3d373d3d3d363d7394b4dfd9ba5865cc931195c99a2db42f3fc5d45b5af43d82803e903d91602b57fd5bf3`\n    // that yield the following hashes, against which we can compare the result of `EXTCODEHASH` to\n    // check whether it is from this factory or not.\n    // This check is very local, so we do not include it in the `CurveRegistryCache`.\n    // Note that other pools may have `price_oracle` that do not check for reentrancy, so we cannot\n    // rely on this check for any pool with the `price_oracle` function.\n    // We only include the hash codes of pools created through factories, because\n    // the bytecode is otherwise slightly different for each pool\n    // Since this is only an optimization for gas purposes, we choose to make this constant,\n    // even if that means that we might miss this optimization for new factories deployed later.\n    bytes32 internal constant ETH_FACTORY_POOL_CODE_HASH_1 =\n        0x9e28a09452d2354fc4e15e3244dde27cbc4d52f12a10b91f2ca755b672bfa9be;\n    bytes32 internal constant ETH_FACTORY_POOL_CODE_HASH_2 =\n        0x3429b8decaf6b79a2721e434f60c3c47b9961fdba16eb6ac6c50d3690ac25276;\n\n    IController internal immutable controller;\n\n    constructor(address controller_) {\n        controller = IController(controller_);\n    }\n\n    /// @notice Deposits single sided liquidity into a Curve pool\n    /// @dev This supports both v1 and v2 (crypto) pools.\n    /// @param _curvePool Curve pool to deposit into\n    /// @param _token Asset to deposit\n    /// @param _amount Amount of asset to deposit\n    function deposit(address _curvePool, address _token, uint256 _amount) public override {\n        ICurveRegistryCache registry_ = controller.curveRegistryCache();\n        bool isETH = _isETH(_curvePool, _token);\n        if (!registry_.hasCoinDirectly(_curvePool, isETH ? _ETH_ADDRESS : _token)) {\n            address intermediate = registry_.basePool(_curvePool);\n            require(intermediate != address(0), \"CurveHandler: intermediate not found\");\n            address lpToken = registry_.lpToken(intermediate);\n            uint256 balanceBefore = ILpToken(lpToken).balanceOf(address(this));\n            _addLiquidity(intermediate, _amount, _token);\n            _token = lpToken;\n            _amount = ILpToken(_token).balanceOf(address(this)) - balanceBefore;\n        }\n        _addLiquidity(_curvePool, _amount, _token);\n    }\n\n    /// @notice Withdraws single sided liquidity from a Curve pool\n    /// @param _curvePool Curve pool to withdraw from\n    /// @param _token Underlying asset to withdraw\n    /// @param _amount Amount of Curve LP tokens to withdraw\n    function withdraw(address _curvePool, address _token, uint256 _amount) external override {\n        ICurveRegistryCache registry_ = controller.curveRegistryCache();\n        bool isETH = _isETH(_curvePool, _token);\n        if (!registry_.hasCoinDirectly(_curvePool, isETH ? _ETH_ADDRESS : _token)) {\n            address intermediate = registry_.basePool(_curvePool);\n            require(intermediate != address(0), \"CurveHandler: intermediate not found\");\n            address lpToken = registry_.lpToken(intermediate);\n            uint256 balanceBefore = ILpToken(lpToken).balanceOf(address(this));\n            _removeLiquidity(_curvePool, _amount, lpToken);\n            _curvePool = intermediate;\n            _amount = ILpToken(lpToken).balanceOf(address(this)) - balanceBefore;\n        }\n\n        _removeLiquidity(_curvePool, _amount, _token);\n    }\n\n    function isReentrantCall(address _curvePool) public override returns (bool) {\n        // In this version, curve pools have a price oracle that has a reentrancy lock\n        // so this call will only succeed if we are not in a reentrant call\n        // This is cheaper than trying to do an exchange\n        bytes32 codeHash = _curvePool.codehash;\n        if (codeHash == ETH_FACTORY_POOL_CODE_HASH_1 || codeHash == ETH_FACTORY_POOL_CODE_HASH_2) {\n            try ICurvePoolV2Eth(_curvePool).price_oracle() {\n                return false;\n            } catch {\n                return true;\n            }\n        }\n\n        uint256 interfaceVersion_ = controller.curveRegistryCache().interfaceVersion(_curvePool);\n        bool ethIndexFirst_ = _isEthIndexFirst(_curvePool);\n\n        // If we don't have any other way to check for reentrancy, we try to do a swap\n        // with 0 amount, which can behave in 3 ways depending on the state and the pool:\n        // 1. If it succeeds, there was definitely no lock in place, so the call is not reentrant\n        // 2. If it fails, it can fail in 2 ways:\n        //   a. It fails because some pools do not allow to swap 0 amount. This also means that the call is non-reentrant\n        //   b. It fails because there is a reentrancy lock in place, which means that the call is reentrant\n        // Checking for case 1 is trivial. For case 2a vs 2b, we check the amount of gas consumed by the call.\n        // Some more details about the values are given in the comments of `LOCK_GAS_THRESHOLD`\n        uint256 gasUsed;\n        uint256 currentGasLeft = gasleft();\n        if (interfaceVersion_ == 2) {\n            try\n                ICurvePoolV2Eth(_curvePool).exchange(\n                    ethIndexFirst_ ? uint256(0) : uint256(1),\n                    ethIndexFirst_ ? uint256(1) : uint256(0),\n                    uint256(0),\n                    uint256(0)\n                )\n            {\n                return false;\n            } catch {\n                gasUsed = currentGasLeft - gasleft();\n            }\n        } else {\n            try\n                ICurvePoolV1Eth(_curvePool).exchange(\n                    ethIndexFirst_ ? int128(0) : int128(1),\n                    ethIndexFirst_ ? int128(1) : int128(0),\n                    uint256(0),\n                    uint256(0)\n                )\n            {\n                return false;\n            } catch {\n                gasUsed = currentGasLeft - gasleft();\n            }\n        }\n\n        return gasUsed < LOCK_GAS_THRESHOLD;\n    }\n\n    /// @notice Validates if a given Curve pool is currently in reentrancy\n    /// @dev Reverts if it is in reentrancy\n    /// @param _curvePool Curve pool to validate\n    function reentrancyCheck(address _curvePool) external override {\n        require(!isReentrantCall(_curvePool), \"CurveHandler: reentrant call\");\n    }\n\n    function _removeLiquidity(\n        address _curvePool,\n        uint256 _amount, // Curve LP token amount\n        address _token // underlying asset to withdraw\n    ) internal {\n        bool isETH = _isETH(_curvePool, _token);\n        int128 index = controller.curveRegistryCache().coinIndex(\n            _curvePool,\n            isETH ? _ETH_ADDRESS : _token\n        );\n\n        uint256 balanceBeforeWithdraw = address(this).balance;\n\n        uint256 interfaceVersion_ = controller.curveRegistryCache().interfaceVersion(_curvePool);\n        if (interfaceVersion_ == 0) {\n            _version_0_remove_liquidity_one_coin(_curvePool, _amount, index);\n        } else if (_hasDynamicAddLiquidity(_curvePool)) {\n            ICurvePoolV7(_curvePool).remove_liquidity_one_coin(_amount, index, 0);\n        } else if (interfaceVersion_ == 1) {\n            ICurvePoolV1(_curvePool).remove_liquidity_one_coin(_amount, index, 0);\n        } else if (interfaceVersion_ == 2) {\n            ICurvePoolV2(_curvePool).remove_liquidity_one_coin(\n                _amount,\n                uint256(uint128(index)),\n                0,\n                isETH,\n                address(this)\n            );\n        } else {\n            revert(\"CurveHandler: unsupported interface version\");\n        }\n\n        if (isETH) {\n            uint256 balanceIncrease = address(this).balance - balanceBeforeWithdraw;\n            _wrapWETH(balanceIncrease);\n        }\n    }\n\n    /// Version 0 pools don't have a `remove_liquidity_one_coin` function.\n    /// So we work around this by calling `removing_liquidity`\n    /// and then swapping all the coins to the target\n    function _version_0_remove_liquidity_one_coin(\n        address _curvePool,\n        uint256 _amount,\n        int128 _index\n    ) internal {\n        ICurveRegistryCache registry_ = controller.curveRegistryCache();\n        uint256 coins = registry_.nCoins(_curvePool);\n        if (coins == 2) {\n            uint256[2] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 3) {\n            uint256[3] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 4) {\n            uint256[4] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 5) {\n            uint256[5] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 6) {\n            uint256[6] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 7) {\n            uint256[7] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else if (coins == 8) {\n            uint256[8] memory min_amounts;\n            ICurvePoolV0(_curvePool).remove_liquidity(_amount, min_amounts);\n        } else {\n            revert(\"CurveHandler: unsupported coins\");\n        }\n\n        for (uint256 i = 0; i < coins; i++) {\n            if (i == uint256(int256(_index))) continue;\n            address[] memory coins_ = registry_.coins(_curvePool);\n            address coin_ = coins_[i];\n            uint256 balance_ = IERC20(coin_).balanceOf(address(this));\n            if (balance_ == 0) continue;\n            IERC20(coin_).forceApprove(_curvePool, balance_);\n            ICurvePoolV0(_curvePool).exchange(int128(int256(i)), _index, balance_, 0);\n        }\n    }\n\n    function _wrapWETH(uint256 amount) internal {\n        _WETH.deposit{value: amount}();\n    }\n\n    function _unwrapWETH(uint256 amount) internal {\n        _WETH.withdraw(amount);\n    }\n\n    function _addLiquidity(\n        address _curvePool,\n        uint256 _amount, // amount of asset to deposit\n        address _token // asset to deposit\n    ) internal {\n        bool isETH = _isETH(_curvePool, _token);\n        if (!isETH) {\n            IERC20(_token).forceApprove(_curvePool, _amount);\n        }\n\n        ICurveRegistryCache registry_ = controller.curveRegistryCache();\n        uint256 index = uint128(registry_.coinIndex(_curvePool, isETH ? _ETH_ADDRESS : _token));\n        uint256 coins = registry_.nCoins(_curvePool);\n        if (_hasDynamicAddLiquidity(_curvePool)) {\n            uint256[] memory amounts = new uint256[](coins);\n            amounts[index] = _amount;\n            ICurvePoolV7(_curvePool).add_liquidity(amounts, 0);\n        } else if (coins == 2) {\n            uint256[2] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 3) {\n            uint256[3] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 4) {\n            uint256[4] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 5) {\n            uint256[5] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 6) {\n            uint256[6] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 7) {\n            uint256[7] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else if (coins == 8) {\n            uint256[8] memory amounts;\n            amounts[index] = _amount;\n            if (isETH) {\n                _unwrapWETH(_amount);\n                ICurvePoolV1Eth(_curvePool).add_liquidity{value: _amount}(amounts, 0);\n            } else {\n                ICurvePoolV1(_curvePool).add_liquidity(amounts, 0);\n            }\n        } else {\n            revert(\"invalid number of coins for curve pool\");\n        }\n    }\n\n    function _isETH(address pool, address token) internal view returns (bool) {\n        return\n            token == address(_WETH) &&\n            controller.curveRegistryCache().hasCoinDirectly(pool, _ETH_ADDRESS);\n    }\n\n    function _isETH(address pool) internal view returns (bool) {\n        return controller.curveRegistryCache().hasCoinDirectly(pool, _ETH_ADDRESS);\n    }\n\n    function _isEthIndexFirst(address pool) internal view returns (bool) {\n        return controller.curveRegistryCache().coinIndex(pool, address(_WETH)) == int128(0);\n    }\n\n    function _hasDynamicAddLiquidity(address pool) internal view returns (bool) {\n        try ICurvePoolV7(pool).version() returns (string memory version) {\n            uint256 majorVersion = StringUtils.extractMajorVersion(version);\n            return majorVersion >= 7;\n        } catch {\n            return false;\n        }\n    }\n}\n"
      },
      "SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"IERC20.sol\";\nimport \"IERC20Permit.sol\";\nimport \"Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "ILpToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"IERC20Metadata.sol\";\n\ninterface ILpToken is IERC20Metadata {\n    function minter() external view returns (address);\n\n    function mint(address account, uint256 amount, address ubo) external returns (uint256);\n\n    function burn(address _owner, uint256 _amount, address ubo) external returns (uint256);\n\n    function taint(address from, address to, uint256 amount) external;\n}\n"
      },
      "IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "ICurveHandler.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface ICurveHandler {\n    function deposit(address _curvePool, address _token, uint256 _amount) external;\n\n    function withdraw(address _curvePool, address _token, uint256 _amount) external;\n\n    function reentrancyCheck(address _curvePool) external;\n\n    function isReentrantCall(address _curvePool) external returns (bool);\n}\n"
      },
      "ICurveRegistryCache.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"IBooster.sol\";\nimport \"CurvePoolUtils.sol\";\nimport \"Types.sol\";\n\ninterface ICurveRegistryCache {\n    event PoolInitialized(address indexed pool, uint256 indexed pid);\n\n    function BOOSTER() external view returns (IBooster);\n\n    function initPool(address pool_) external;\n\n    function initPool(address pool_, uint256 pid_) external;\n\n    function initPool(address pool_, Types.PoolInfo memory poolInfo_) external;\n\n    function initPool(address pool_, uint256 pid_, Types.PoolInfo memory poolInfo_) external;\n\n    function lpToken(address pool_) external view returns (address);\n\n    function assetType(address pool_) external view returns (CurvePoolUtils.AssetType);\n\n    function isRegistered(address pool_) external view returns (bool);\n\n    function hasCoinDirectly(address pool_, address coin_) external view returns (bool);\n\n    function hasCoinAnywhere(address pool_, address coin_) external view returns (bool);\n\n    function basePool(address pool_) external view returns (address);\n\n    function coinIndex(address pool_, address coin_) external view returns (int128);\n\n    function nCoins(address pool_) external view returns (uint256);\n\n    function coinIndices(\n        address pool_,\n        address from_,\n        address to_\n    ) external view returns (int128, int128, bool);\n\n    function decimals(address pool_) external view returns (uint256[] memory);\n\n    function interfaceVersion(address pool_) external view returns (uint256);\n\n    function poolFromLpToken(address lpToken_) external view returns (address);\n\n    function coins(address pool_) external view returns (address[] memory);\n\n    function getPid(address _pool) external view returns (uint256);\n\n    function getRewardPool(address _pool) external view returns (address);\n\n    function isShutdownPid(uint256 pid_) external view returns (bool);\n\n    /// @notice this returns the underlying coins of a pool, including the underlying of the base pool\n    /// if the given pool is a meta pool\n    /// This does not return the LP token of the base pool as an underlying\n    /// e.g. if the pool is 3CrvFrax, this will return FRAX, DAI, USDC, USDT\n    function getAllUnderlyingCoins(address pool) external view returns (address[] memory);\n}\n"
      },
      "IBooster.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface IBooster {\n    function poolInfo(\n        uint256 pid\n    )\n        external\n        view\n        returns (\n            address lpToken,\n            address token,\n            address gauge,\n            address crvRewards,\n            address stash,\n            bool shutdown\n        );\n\n    function poolLength() external view returns (uint256);\n\n    function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns (bool);\n\n    function withdraw(uint256 _pid, uint256 _amount) external returns (bool);\n\n    function withdrawAll(uint256 _pid) external returns (bool);\n\n    function depositAll(uint256 _pid, bool _stake) external returns (bool);\n\n    function earmarkRewards(uint256 _pid) external returns (bool);\n\n    function isShutdown() external view returns (bool);\n}\n"
      },
      "CurvePoolUtils.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"ICurvePoolV2.sol\";\nimport \"ICurvePoolV1.sol\";\nimport \"ScaledMath.sol\";\n\nlibrary CurvePoolUtils {\n    using ScaledMath for uint256;\n\n    error NotWithinThreshold(address pool, uint256 assetA, uint256 assetB);\n\n    /// @dev by default, allow for 30 bps deviation regardless of pool fees\n    uint256 internal constant _DEFAULT_IMBALANCE_BUFFER = 30e14;\n\n    /// @dev Curve scales the `fee` by 1e10\n    uint8 internal constant _CURVE_POOL_FEE_DECIMALS = 10;\n\n    /// @dev allow imbalance to be buffer + 3x the fee, e.g. if fee is 3.6 bps and buffer is 30 bps, allow 40.8 bps\n    uint256 internal constant _FEE_IMBALANCE_MULTIPLIER = 3;\n\n    enum AssetType {\n        USD,\n        ETH,\n        BTC,\n        OTHER,\n        CRYPTO\n    }\n\n    struct PoolMeta {\n        address pool;\n        uint256 numberOfCoins;\n        AssetType assetType;\n        uint256[] decimals;\n        uint256[] prices;\n        uint256[] imbalanceBuffers;\n    }\n\n    function ensurePoolBalanced(PoolMeta memory poolMeta) internal view {\n        uint256 poolFee = ICurvePoolV1(poolMeta.pool).fee().convertScale(\n            _CURVE_POOL_FEE_DECIMALS,\n            18\n        );\n\n        for (uint256 i = 0; i < poolMeta.numberOfCoins - 1; i++) {\n            uint256 fromDecimals = poolMeta.decimals[i];\n            uint256 fromBalance = 10 ** fromDecimals;\n            uint256 fromPrice = poolMeta.prices[i];\n\n            for (uint256 j = i + 1; j < poolMeta.numberOfCoins; j++) {\n                uint256 toDecimals = poolMeta.decimals[j];\n                uint256 toPrice = poolMeta.prices[j];\n                uint256 toExpectedUnscaled = (fromBalance * fromPrice) / toPrice;\n                uint256 toExpected = toExpectedUnscaled.convertScale(\n                    uint8(fromDecimals),\n                    uint8(toDecimals)\n                );\n\n                uint256 toActual;\n\n                if (poolMeta.assetType == AssetType.CRYPTO) {\n                    // Handling crypto pools\n                    toActual = ICurvePoolV2(poolMeta.pool).get_dy(i, j, fromBalance);\n                } else {\n                    // Handling other pools\n                    toActual = ICurvePoolV1(poolMeta.pool).get_dy(\n                        int128(uint128(i)),\n                        int128(uint128(j)),\n                        fromBalance\n                    );\n                }\n                uint256 _maxImbalanceBuffer = poolMeta.imbalanceBuffers[i].max(\n                    poolMeta.imbalanceBuffers[j]\n                );\n\n                if (!_isWithinThreshold(toExpected, toActual, poolFee, _maxImbalanceBuffer))\n                    revert NotWithinThreshold(poolMeta.pool, i, j);\n            }\n        }\n    }\n\n    function _isWithinThreshold(\n        uint256 a,\n        uint256 b,\n        uint256 poolFee,\n        uint256 imbalanceBuffer\n    ) internal pure returns (bool) {\n        if (imbalanceBuffer == 0) imbalanceBuffer = _DEFAULT_IMBALANCE_BUFFER;\n        uint256 imbalanceTreshold = imbalanceBuffer + poolFee * _FEE_IMBALANCE_MULTIPLIER;\n        if (a > b) return (a - b).divDown(a) <= imbalanceTreshold;\n        return (b - a).divDown(b) <= imbalanceTreshold;\n    }\n}\n"
      },
      "ICurvePoolV2.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV2 {\n    function token() external view returns (address);\n\n    function coins(uint256 i) external view returns (address);\n\n    function factory() external view returns (address);\n\n    function exchange(\n        uint256 i,\n        uint256 j,\n        uint256 dx,\n        uint256 min_dy,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function exchange_underlying(\n        uint256 i,\n        uint256 j,\n        uint256 dx,\n        uint256 min_dy,\n        address receiver\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[2] memory amounts,\n        uint256 min_mint_amount,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[2] memory amounts,\n        uint256 min_mint_amount\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[3] memory amounts,\n        uint256 min_mint_amount,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[3] memory amounts,\n        uint256 min_mint_amount\n    ) external returns (uint256);\n\n    function remove_liquidity(\n        uint256 _amount,\n        uint256[2] memory min_amounts,\n        bool use_eth,\n        address receiver\n    ) external;\n\n    function remove_liquidity(uint256 _amount, uint256[2] memory min_amounts) external;\n\n    function remove_liquidity(\n        uint256 _amount,\n        uint256[3] memory min_amounts,\n        bool use_eth,\n        address receiver\n    ) external;\n\n    function remove_liquidity(uint256 _amount, uint256[3] memory min_amounts) external;\n\n    function remove_liquidity_one_coin(\n        uint256 token_amount,\n        uint256 i,\n        uint256 min_amount,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);\n\n    function calc_token_amount(uint256[] memory amounts) external view returns (uint256);\n\n    function calc_withdraw_one_coin(\n        uint256 token_amount,\n        uint256 i\n    ) external view returns (uint256);\n\n    function get_virtual_price() external view returns (uint256);\n}\n"
      },
      "ICurvePoolV1.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV1 {\n    function get_virtual_price() external view returns (uint256);\n\n    function add_liquidity(uint256[8] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[7] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[6] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[5] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external;\n\n    function remove_liquidity_imbalance(\n        uint256[4] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_imbalance(\n        uint256[3] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_imbalance(\n        uint256[2] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function lp_token() external view returns (address);\n\n    function A_PRECISION() external view returns (uint256);\n\n    function A_precise() external view returns (uint256);\n\n    function remove_liquidity(uint256 _amount, uint256[3] calldata min_amounts) external;\n\n    function exchange(\n        int128 from,\n        int128 to,\n        uint256 _from_amount,\n        uint256 _min_to_amount\n    ) external;\n\n    function coins(uint256 i) external view returns (address);\n\n    function balances(uint256 i) external view returns (uint256);\n\n    function get_dy(int128 i, int128 j, uint256 _dx) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[4] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[3] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[2] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_withdraw_one_coin(\n        uint256 _token_amount,\n        int128 i\n    ) external view returns (uint256);\n\n    function remove_liquidity_one_coin(\n        uint256 _token_amount,\n        int128 i,\n        uint256 min_amount\n    ) external;\n\n    function fee() external view returns (uint256);\n}\n"
      },
      "ScaledMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nlibrary ScaledMath {\n    uint256 internal constant DECIMALS = 18;\n    uint256 internal constant ONE = 10 ** DECIMALS;\n\n    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {\n        return (a * b) / ONE;\n    }\n\n    function mulDown(uint256 a, uint256 b, uint256 decimals) internal pure returns (uint256) {\n        return (a * b) / (10 ** decimals);\n    }\n\n    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {\n        return (a * ONE) / b;\n    }\n\n    function divDown(uint256 a, uint256 b, uint256 decimals) internal pure returns (uint256) {\n        return (a * 10 ** decimals) / b;\n    }\n\n    function divUp(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n        return ((a * ONE) - 1) / b + 1;\n    }\n\n    function mulDown(int256 a, int256 b) internal pure returns (int256) {\n        return (a * b) / int256(ONE);\n    }\n\n    function mulDownUint128(uint128 a, uint128 b) internal pure returns (uint128) {\n        return (a * b) / uint128(ONE);\n    }\n\n    function mulDown(int256 a, int256 b, uint256 decimals) internal pure returns (int256) {\n        return (a * b) / int256(10 ** decimals);\n    }\n\n    function divDown(int256 a, int256 b) internal pure returns (int256) {\n        return (a * int256(ONE)) / b;\n    }\n\n    function divDownUint128(uint128 a, uint128 b) internal pure returns (uint128) {\n        return (a * uint128(ONE)) / b;\n    }\n\n    function divDown(int256 a, int256 b, uint256 decimals) internal pure returns (int256) {\n        return (a * int256(10 ** decimals)) / b;\n    }\n\n    function convertScale(\n        uint256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (uint256) {\n        if (fromDecimals == toDecimals) return a;\n        if (fromDecimals > toDecimals) return downscale(a, fromDecimals, toDecimals);\n        return upscale(a, fromDecimals, toDecimals);\n    }\n\n    function convertScale(\n        int256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (int256) {\n        if (fromDecimals == toDecimals) return a;\n        if (fromDecimals > toDecimals) return downscale(a, fromDecimals, toDecimals);\n        return upscale(a, fromDecimals, toDecimals);\n    }\n\n    function upscale(\n        uint256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (uint256) {\n        return a * (10 ** (toDecimals - fromDecimals));\n    }\n\n    function downscale(\n        uint256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (uint256) {\n        return a / (10 ** (fromDecimals - toDecimals));\n    }\n\n    function upscale(\n        int256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (int256) {\n        return a * int256(10 ** (toDecimals - fromDecimals));\n    }\n\n    function downscale(\n        int256 a,\n        uint8 fromDecimals,\n        uint8 toDecimals\n    ) internal pure returns (int256) {\n        return a / int256(10 ** (fromDecimals - toDecimals));\n    }\n\n    function intPow(uint256 a, uint256 n) internal pure returns (uint256) {\n        uint256 result = ONE;\n        for (uint256 i; i < n; ) {\n            result = mulDown(result, a);\n            unchecked {\n                ++i;\n            }\n        }\n        return result;\n    }\n\n    function absSub(uint256 a, uint256 b) internal pure returns (uint256) {\n        unchecked {\n            return a >= b ? a - b : b - a;\n        }\n    }\n\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a >= b ? a : b;\n    }\n\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a <= b ? a : b;\n    }\n}\n"
      },
      "Types.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nlibrary Types {\n    struct Coin {\n        address coinAddress;\n        uint8 decimals;\n    }\n\n    struct CliffInfo {\n        uint256 currentCliff;\n        bool withinThreshold;\n    }\n\n    struct PoolInfo {\n        address lpToken;\n        address basePool;\n        uint256 assetType;\n    }\n}\n"
      },
      "IWETH.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"IERC20.sol\";\n\ninterface IWETH is IERC20 {\n    function deposit() external payable;\n\n    function withdraw(uint256 wad) external;\n}\n"
      },
      "ICurvePoolV0.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV0 {\n    function get_virtual_price() external view returns (uint256);\n\n    function add_liquidity(uint256[8] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[7] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[6] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[5] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external;\n\n    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external;\n\n    function remove_liquidity_imbalance(\n        uint256[4] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_imbalance(\n        uint256[3] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_imbalance(\n        uint256[2] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function lp_token() external view returns (address);\n\n    function A_PRECISION() external view returns (uint256);\n\n    function A_precise() external view returns (uint256);\n\n    function remove_liquidity(uint256 _amount, uint256[2] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[3] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[4] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[5] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[6] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[7] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[8] calldata min_amounts) external;\n\n    function exchange(\n        int128 from,\n        int128 to,\n        uint256 _from_amount,\n        uint256 _min_to_amount\n    ) external;\n\n    function coins(int128 i) external view returns (address);\n\n    function balances(int128 i) external view returns (uint256);\n\n    function get_dy(int128 i, int128 j, uint256 _dx) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[4] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[3] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[2] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_withdraw_one_coin(\n        uint256 _token_amount,\n        int128 i\n    ) external view returns (uint256);\n}\n"
      },
      "ICurvePoolV7.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV7 {\n    function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external returns (uint256);\n\n    function exchange(\n        int128 i,\n        int128 j,\n        uint256 _dx,\n        uint256 _min_dy,\n        address _receiver\n    ) external returns (uint256);\n\n    function exchange_received(\n        int128 i,\n        int128 j,\n        uint256 _dx,\n        uint256 _min_dy\n    ) external returns (uint256);\n\n    function exchange_received(\n        int128 i,\n        int128 j,\n        uint256 _dx,\n        uint256 _min_dy,\n        address _receiver\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[] memory _amounts,\n        uint256 _min_mint_amount\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[] memory _amounts,\n        uint256 _min_mint_amount,\n        address _receiver\n    ) external returns (uint256);\n\n    function remove_liquidity_one_coin(\n        uint256 _burn_amount,\n        int128 i,\n        uint256 _min_received\n    ) external returns (uint256);\n\n    function remove_liquidity_one_coin(\n        uint256 _burn_amount,\n        int128 i,\n        uint256 _min_received,\n        address _receiver\n    ) external returns (uint256);\n\n    function remove_liquidity_imbalance(\n        uint256[] memory _amounts,\n        uint256 _max_burn_amount\n    ) external returns (uint256);\n\n    function remove_liquidity_imbalance(\n        uint256[] memory _amounts,\n        uint256 _max_burn_amount,\n        address _receiver\n    ) external returns (uint256);\n\n    function remove_liquidity(\n        uint256 _burn_amount,\n        uint256[] memory _min_amounts\n    ) external returns (uint256[] memory);\n\n    function remove_liquidity(\n        uint256 _burn_amount,\n        uint256[] memory _min_amounts,\n        address _receiver\n    ) external returns (uint256[] memory);\n\n    function remove_liquidity(\n        uint256 _burn_amount,\n        uint256[] memory _min_amounts,\n        address _receiver,\n        bool _claim_admin_fees\n    ) external returns (uint256[] memory);\n\n    function withdraw_admin_fees() external;\n\n    function last_price(uint256 i) external view returns (uint256);\n\n    function ema_price(uint256 i) external view returns (uint256);\n\n    function get_p(uint256 i) external view returns (uint256);\n\n    function price_oracle(uint256 i) external view returns (uint256);\n\n    function D_oracle() external view returns (uint256);\n\n    function transfer(address _to, uint256 _value) external returns (bool);\n\n    function transferFrom(address _from, address _to, uint256 _value) external returns (bool);\n\n    function approve(address _spender, uint256 _value) external returns (bool);\n\n    function permit(\n        address _owner,\n        address _spender,\n        uint256 _value,\n        uint256 _deadline,\n        uint8 _v,\n        bytes32 _r,\n        bytes32 _s\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function get_dx(int128 i, int128 j, uint256 dy) external view returns (uint256);\n\n    function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);\n\n    function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);\n\n    function totalSupply() external view returns (uint256);\n\n    function get_virtual_price() external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[] memory _amounts,\n        bool _is_deposit\n    ) external view returns (uint256);\n\n    function A() external view returns (uint256);\n\n    function A_precise() external view returns (uint256);\n\n    function balances(uint256 i) external view returns (uint256);\n\n    function get_balances() external view returns (uint256[] memory);\n\n    function stored_rates() external view returns (uint256[] memory);\n\n    function dynamic_fee(int128 i, int128 j) external view returns (uint256);\n\n    function ramp_A(uint256 _future_A, uint256 _future_time) external;\n\n    function stop_ramp_A() external;\n\n    function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier) external;\n\n    function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;\n\n    function N_COINS() external view returns (uint256);\n\n    function coins(uint256 arg0) external view returns (address);\n\n    function fee() external view returns (uint256);\n\n    function offpeg_fee_multiplier() external view returns (uint256);\n\n    function admin_fee() external view returns (uint256);\n\n    function initial_A() external view returns (uint256);\n\n    function future_A() external view returns (uint256);\n\n    function initial_A_time() external view returns (uint256);\n\n    function future_A_time() external view returns (uint256);\n\n    function admin_balances(uint256 arg0) external view returns (uint256);\n\n    function ma_exp_time() external view returns (uint256);\n\n    function D_ma_time() external view returns (uint256);\n\n    function ma_last_time() external view returns (uint256);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function version() external view returns (string memory);\n\n    function balanceOf(address arg0) external view returns (uint256);\n\n    function allowance(address arg0, address arg1) external view returns (uint256);\n\n    function nonces(address arg0) external view returns (uint256);\n\n    function salt() external view returns (bytes32);\n}\n"
      },
      "ICurvePoolV1Eth.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV1Eth {\n    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[5] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[6] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[7] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function add_liquidity(uint256[8] calldata amounts, uint256 min_mint_amount) external payable;\n\n    function remove_liquidity_imbalance(\n        uint256[3] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_imbalance(\n        uint256[2] calldata amounts,\n        uint256 max_burn_amount\n    ) external;\n\n    function remove_liquidity_one_coin(\n        uint256 _token_amount,\n        int128 i,\n        uint256 min_amount\n    ) external;\n\n    function remove_liquidity(uint256 _amount, uint256[2] calldata min_amounts) external;\n\n    function remove_liquidity(uint256 _amount, uint256[3] calldata min_amounts) external;\n\n    function get_virtual_price() external view returns (uint256);\n\n    function coins(uint256 i) external view returns (address);\n\n    function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[3] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[2] calldata amounts,\n        bool deposit\n    ) external view returns (uint256);\n\n    function calc_withdraw_one_coin(\n        uint256 _token_amount,\n        int128 i\n    ) external view returns (uint256);\n\n    function exchange(\n        int128 from,\n        int128 to,\n        uint256 _from_amount,\n        uint256 _min_to_amount\n    ) external payable;\n}\n"
      },
      "ICurvePoolV2Eth.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.17;\n\ninterface ICurvePoolV2Eth {\n    function token() external view returns (address);\n\n    function coins(uint256 i) external view returns (address);\n\n    function factory() external view returns (address);\n\n    function exchange(\n        uint256 i,\n        uint256 j,\n        uint256 dx,\n        uint256 min_dy\n    ) external payable returns (uint256);\n\n    function exchange(\n        uint256 i,\n        uint256 j,\n        uint256 dx,\n        uint256 min_dy,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function exchange_underlying(\n        uint256 i,\n        uint256 j,\n        uint256 dx,\n        uint256 min_dy,\n        address receiver\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[2] memory amounts,\n        uint256 min_mint_amount,\n        bool use_eth,\n        address receiver\n    ) external payable returns (uint256);\n\n    function add_liquidity(\n        uint256[2] memory amounts,\n        uint256 min_mint_amount\n    ) external returns (uint256);\n\n    function add_liquidity(\n        uint256[3] memory amounts,\n        uint256 min_mint_amount,\n        bool use_eth,\n        address receiver\n    ) external payable returns (uint256);\n\n    function add_liquidity(\n        uint256[3] memory amounts,\n        uint256 min_mint_amount\n    ) external returns (uint256);\n\n    function remove_liquidity(\n        uint256 _amount,\n        uint256[2] memory min_amounts,\n        bool use_eth,\n        address receiver\n    ) external;\n\n    function remove_liquidity(uint256 _amount, uint256[2] memory min_amounts) external;\n\n    function remove_liquidity(\n        uint256 _amount,\n        uint256[3] memory min_amounts,\n        bool use_eth,\n        address receiver\n    ) external;\n\n    function remove_liquidity(uint256 _amount, uint256[3] memory min_amounts) external;\n\n    function remove_liquidity_one_coin(\n        uint256 token_amount,\n        uint256 i,\n        uint256 min_amount,\n        bool use_eth,\n        address receiver\n    ) external returns (uint256);\n\n    function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);\n\n    function calc_token_amount(uint256[] memory amounts) external view returns (uint256);\n\n    function calc_withdraw_one_coin(\n        uint256 token_amount,\n        uint256 i\n    ) external view returns (uint256);\n\n    function get_virtual_price() external view returns (uint256);\n\n    function price_oracle() external view returns (uint256);\n\n    function apply_new_parameters() external;\n}\n"
      },
      "IController.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"IConicPoolWeightManagement.sol\";\nimport \"IConicPool.sol\";\nimport \"IGenericOracle.sol\";\nimport \"IInflationManager.sol\";\nimport \"ILpTokenStaker.sol\";\nimport \"IBonding.sol\";\nimport \"IPoolAdapter.sol\";\nimport \"IFeeRecipient.sol\";\nimport \"ICurveRegistryCache.sol\";\n\ninterface IController {\n    event PoolAdded(address indexed pool);\n    event PoolRemoved(address indexed pool);\n    event PoolShutdown(address indexed pool);\n    event ConvexBoosterSet(address convexBooster);\n    event CurveHandlerSet(address curveHandler);\n    event ConvexHandlerSet(address convexHandler);\n    event CurveRegistryCacheSet(address curveRegistryCache);\n    event InflationManagerSet(address inflationManager);\n    event BondingSet(address bonding);\n    event FeeRecipientSet(address feeRecipient);\n    event PriceOracleSet(address priceOracle);\n    event WeightUpdateMinDelaySet(uint256 weightUpdateMinDelay);\n    event PauseManagerSet(address indexed manager, bool isManager);\n    event MultiDepositsWithdrawsWhitelistSet(address pool, bool allowed);\n    event MinimumTaintedTransferAmountSet(address indexed token, uint256 amount);\n    event DefaultPoolAdapterSet(address poolAdapter);\n    event CustomPoolAdapterSet(address indexed pool, address poolAdapter);\n\n    struct WeightUpdate {\n        address conicPoolAddress;\n        IConicPoolWeightManagement.PoolWeight[] weights;\n    }\n\n    function initialize(address _lpTokenStaker) external;\n\n    // inflation manager\n\n    function inflationManager() external view returns (IInflationManager);\n\n    function setInflationManager(address manager) external;\n\n    // views\n    function curveRegistryCache() external view returns (ICurveRegistryCache);\n\n    // pool adapter\n    function poolAdapterFor(address pool) external view returns (IPoolAdapter);\n\n    function defaultPoolAdapter() external view returns (IPoolAdapter);\n\n    function setDefaultPoolAdapter(address poolAdapter) external;\n\n    function setCustomPoolAdapter(address pool, address poolAdapter) external;\n\n    /// lp token staker\n    function switchLpTokenStaker(address _lpTokenStaker) external;\n\n    function lpTokenStaker() external view returns (ILpTokenStaker);\n\n    // bonding\n    function bonding() external view returns (IBonding);\n\n    function setBonding(address _bonding) external;\n\n    // fees\n    function feeRecipient() external view returns (IFeeRecipient);\n\n    function setFeeRecipient(address _feeRecipient) external;\n\n    // oracle\n    function priceOracle() external view returns (IGenericOracle);\n\n    function setPriceOracle(address oracle) external;\n\n    // pool functions\n\n    function listPools() external view returns (address[] memory);\n\n    function listActivePools() external view returns (address[] memory);\n\n    function isPool(address poolAddress) external view returns (bool);\n\n    function isActivePool(address poolAddress) external view returns (bool);\n\n    function addPool(address poolAddress) external;\n\n    function shutdownPool(address poolAddress) external;\n\n    function removePool(address poolAddress) external;\n\n    function cncToken() external view returns (address);\n\n    function lastWeightUpdate(address poolAddress) external view returns (uint256);\n\n    function updateWeights(WeightUpdate memory update) external;\n\n    function updateAllWeights(WeightUpdate[] memory weights) external;\n\n    // handler functions\n\n    function convexBooster() external view returns (address);\n\n    function curveHandler() external view returns (address);\n\n    function convexHandler() external view returns (address);\n\n    function setConvexBooster(address _convexBooster) external;\n\n    function setCurveHandler(address _curveHandler) external;\n\n    function setConvexHandler(address _convexHandler) external;\n\n    function setCurveRegistryCache(address curveRegistryCache_) external;\n\n    function setWeightUpdateMinDelay(uint256 delay) external;\n\n    function isPauseManager(address account) external view returns (bool);\n\n    function listPauseManagers() external view returns (address[] memory);\n\n    function setPauseManager(address account, bool isManager) external;\n\n    // deposit/withdrawal whitelist\n    function isAllowedMultipleDepositsWithdraws(address poolAddress) external view returns (bool);\n\n    function setAllowedMultipleDepositsWithdraws(address account, bool allowed) external;\n\n    function getMultipleDepositsWithdrawsWhitelist() external view returns (address[] memory);\n\n    // tainted transfer amount\n    function setMinimumTaintedTransferAmount(address token, uint256 amount) external;\n\n    function getMinimumTaintedTransferAmount(address token) external view returns (uint256);\n\n    // constants\n\n    function MAX_WEIGHT_UPDATE_MIN_DELAY() external view returns (uint256);\n\n    function MIN_WEIGHT_UPDATE_MIN_DELAY() external view returns (uint256);\n}\n"
      },
      "IConicPoolWeightManagement.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IConicPoolWeightManagement {\n    struct PoolWeight {\n        address poolAddress;\n        uint256 weight;\n    }\n\n    function addPool(address pool) external;\n\n    function removePool(address pool) external;\n\n    function updateWeights(PoolWeight[] memory poolWeights) external;\n\n    function handleDepeggedCurvePool(address curvePool_) external;\n\n    function handleInvalidConvexPid(address pool) external returns (uint256);\n\n    function allPools() external view returns (address[] memory);\n\n    function poolsCount() external view returns (uint256);\n\n    function getPoolAtIndex(uint256 _index) external view returns (address);\n\n    function getWeight(address curvePool) external view returns (uint256);\n\n    function getWeights() external view returns (PoolWeight[] memory);\n\n    function isRegisteredPool(address _pool) external view returns (bool);\n}\n"
      },
      "IConicPool.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"ILpToken.sol\";\nimport \"IRewardManager.sol\";\nimport \"IOracle.sol\";\nimport \"IController.sol\";\nimport \"IPausable.sol\";\nimport \"IConicPoolWeightManagement.sol\";\n\ninterface IConicPool is IConicPoolWeightManagement, IPausable {\n    event Deposit(\n        address indexed sender,\n        address indexed receiver,\n        uint256 depositedAmount,\n        uint256 lpReceived\n    );\n    event Withdraw(address indexed account, uint256 amount);\n    event NewWeight(address indexed curvePool, uint256 newWeight);\n    event NewMaxIdleCurveLpRatio(uint256 newRatio);\n    event ClaimedRewards(uint256 claimedCrv, uint256 claimedCvx);\n    event HandledDepeggedCurvePool(address curvePool_);\n    event HandledInvalidConvexPid(address curvePool_, uint256 pid_);\n    event CurvePoolAdded(address curvePool_);\n    event CurvePoolRemoved(address curvePool_);\n    event Shutdown();\n    event DepegThresholdUpdated(uint256 newThreshold);\n    event MaxDeviationUpdated(uint256 newMaxDeviation);\n    event RebalancingRewardsEnabledSet(bool enabled);\n    event EmergencyRebalancingRewardFactorUpdated(uint256 factor);\n\n    struct PoolWithAmount {\n        address poolAddress;\n        uint256 amount;\n    }\n\n    function underlying() external view returns (IERC20Metadata);\n\n    function lpToken() external view returns (ILpToken);\n\n    function rewardManager() external view returns (IRewardManager);\n\n    function depegThreshold() external view returns (uint256);\n\n    function maxDeviation() external view returns (uint256);\n\n    function maxIdleCurveLpRatio() external view returns (uint256);\n\n    function setMaxIdleCurveLpRatio(uint256 value) external;\n\n    function setMaxDeviation(uint256 maxDeviation_) external;\n\n    function updateDepegThreshold(uint256 value) external;\n\n    function depositFor(\n        address _account,\n        uint256 _amount,\n        uint256 _minLpReceived,\n        bool stake\n    ) external returns (uint256);\n\n    function deposit(uint256 _amount, uint256 _minLpReceived) external returns (uint256);\n\n    function deposit(\n        uint256 _amount,\n        uint256 _minLpReceived,\n        bool stake\n    ) external returns (uint256);\n\n    function exchangeRate() external view returns (uint256);\n\n    function usdExchangeRate() external view returns (uint256);\n\n    function unstakeAndWithdraw(uint256 _amount, uint256 _minAmount) external returns (uint256);\n\n    function unstakeAndWithdraw(\n        uint256 _amount,\n        uint256 _minAmount,\n        address _to\n    ) external returns (uint256);\n\n    function withdraw(uint256 _amount, uint256 _minAmount) external returns (uint256);\n\n    function withdraw(uint256 _amount, uint256 _minAmount, address _to) external returns (uint256);\n\n    function getAllocatedUnderlying() external view returns (PoolWithAmount[] memory);\n\n    function rebalancingRewardActive() external view returns (bool);\n\n    function totalDeviationAfterWeightUpdate() external view returns (uint256);\n\n    function computeTotalDeviation() external view returns (uint256);\n\n    /// @notice returns the total amount of funds held by this pool in terms of underlying\n    function totalUnderlying() external view returns (uint256);\n\n    function getTotalAndPerPoolUnderlying()\n        external\n        view\n        returns (\n            uint256 totalUnderlying_,\n            uint256 totalAllocated_,\n            uint256[] memory perPoolUnderlying_\n        );\n\n    /// @notice same as `totalUnderlying` but returns a cached version\n    /// that might be slightly outdated if oracle prices have changed\n    /// @dev this is useful in cases where we want to reduce gas usage and do\n    /// not need a precise value\n    function cachedTotalUnderlying() external view returns (uint256);\n\n    function updateRewardSpendingApproval(address token, bool approved) external;\n\n    function shutdownPool() external;\n\n    function isShutdown() external view returns (bool);\n\n    function isBalanced() external view returns (bool);\n\n    function rebalancingRewardsEnabled() external view returns (bool);\n\n    function setRebalancingRewardsEnabled(bool enabled) external;\n\n    function getAllUnderlyingCoins() external view returns (address[] memory result);\n\n    function rebalancingRewardsFactor() external view returns (uint256);\n\n    function rebalancingRewardsActivatedAt() external view returns (uint64);\n\n    function getWeights() external view returns (PoolWeight[] memory);\n\n    function runSanityChecks() external;\n}\n"
      },
      "IRewardManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IRewardManager {\n    event ClaimedRewards(uint256 claimedCrv, uint256 claimedCvx);\n    event SoldRewardTokens(uint256 targetTokenReceived);\n    event ExtraRewardAdded(address reward);\n    event ExtraRewardRemoved(address reward);\n    event ExtraRewardsCurvePoolSet(address extraReward, address curvePool);\n    event FeesSet(uint256 feePercentage);\n    event FeesEnabled(uint256 feePercentage);\n    event EarningsClaimed(\n        address indexed claimedBy,\n        uint256 cncEarned,\n        uint256 crvEarned,\n        uint256 cvxEarned\n    );\n\n    function accountCheckpoint(address account) external;\n\n    function poolCheckpoint() external returns (bool);\n\n    function addExtraReward(address reward) external returns (bool);\n\n    function addBatchExtraRewards(address[] memory rewards) external;\n\n    function conicPool() external view returns (address);\n\n    function setFeePercentage(uint256 _feePercentage) external;\n\n    function claimableRewards(\n        address account\n    ) external view returns (uint256 cncRewards, uint256 crvRewards, uint256 cvxRewards);\n\n    function claimEarnings() external returns (uint256, uint256, uint256);\n\n    function claimPoolEarningsAndSellRewardTokens() external;\n\n    function feePercentage() external view returns (uint256);\n\n    function feesEnabled() external view returns (bool);\n}\n"
      },
      "IOracle.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IOracle {\n    event TokenUpdated(address indexed token, address feed, uint256 maxDelay, bool isEthPrice);\n\n    /// @notice returns the price in USD of symbol.\n    function getUSDPrice(address token) external view returns (uint256);\n\n    /// @notice returns if the given token is supported for pricing.\n    function isTokenSupported(address token) external view returns (bool);\n}\n"
      },
      "IPausable.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"Ownable.sol\";\n\nimport \"IController.sol\";\n\ninterface IPausable {\n    event Paused(uint256 pausedUntil);\n    event PauseDurationSet(uint256 pauseDuration);\n\n    function controller() external view returns (IController);\n\n    function pausedUntil() external view returns (uint256);\n\n    function pauseDuration() external view returns (uint256);\n\n    function isPaused() external view returns (bool);\n\n    function setPauseDuration(uint256 _pauseDuration) external;\n\n    function pause() external;\n}\n"
      },
      "Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "IGenericOracle.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nimport \"IOracle.sol\";\n\ninterface IGenericOracle is IOracle {\n    /// @notice returns the oracle to be used to price `token`\n    function getOracle(address token) external view returns (IOracle);\n\n    /// @notice converts the price of an LP token to the given underlying\n    function curveLpToUnderlying(\n        address curveLpToken,\n        address underlying,\n        uint256 curveLpAmount\n    ) external view returns (uint256);\n\n    /// @notice same as above but avoids fetching the underlying price again\n    function curveLpToUnderlying(\n        address curveLpToken,\n        address underlying,\n        uint256 curveLpAmount,\n        uint256 underlyingPrice\n    ) external view returns (uint256);\n\n    /// @notice converts the price an underlying asset to a given Curve LP token\n    function underlyingToCurveLp(\n        address underlying,\n        address curveLpToken,\n        uint256 underlyingAmount\n    ) external view returns (uint256);\n}\n"
      },
      "IInflationManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IInflationManager {\n    event TokensClaimed(address indexed pool, uint256 cncAmount);\n    event RebalancingRewardHandlerAdded(address indexed pool, address indexed handler);\n    event RebalancingRewardHandlerRemoved(address indexed pool, address indexed handler);\n    event PoolWeightsUpdated();\n\n    function executeInflationRateUpdate() external;\n\n    function updatePoolWeights() external;\n\n    /// @notice returns the weights of the Conic pools to know how much inflation\n    /// each of them will receive, as well as the total amount of USD value in all the pools\n    function computePoolWeights()\n        external\n        view\n        returns (address[] memory _pools, uint256[] memory poolWeights, uint256 totalUSDValue);\n\n    function computePoolWeight(\n        address pool\n    ) external view returns (uint256 poolWeight, uint256 totalUSDValue);\n\n    function currentInflationRate() external view returns (uint256);\n\n    function getCurrentPoolInflationRate(address pool) external view returns (uint256);\n\n    function handleRebalancingRewards(\n        address account,\n        uint256 deviationBefore,\n        uint256 deviationAfter\n    ) external;\n\n    function addPoolRebalancingRewardHandler(\n        address poolAddress,\n        address rebalancingRewardHandler\n    ) external;\n\n    function removePoolRebalancingRewardHandler(\n        address poolAddress,\n        address rebalancingRewardHandler\n    ) external;\n\n    function rebalancingRewardHandlers(\n        address poolAddress\n    ) external view returns (address[] memory);\n\n    function hasPoolRebalancingRewardHandler(\n        address poolAddress,\n        address handler\n    ) external view returns (bool);\n}\n"
      },
      "ILpTokenStaker.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface ILpTokenStaker {\n    event LpTokenStaked(address indexed account, uint256 amount);\n    event LpTokenUnstaked(address indexed account, uint256 amount);\n    event TokensClaimed(address indexed pool, uint256 cncAmount);\n    event Shutdown();\n\n    function stake(uint256 amount, address conicPool) external;\n\n    function unstake(uint256 amount, address conicPool) external;\n\n    function stakeFor(uint256 amount, address conicPool, address account) external;\n\n    function unstakeFor(uint256 amount, address conicPool, address account) external;\n\n    function unstakeFrom(uint256 amount, address account) external;\n\n    function getUserBalanceForPool(\n        address conicPool,\n        address account\n    ) external view returns (uint256);\n\n    function getBalanceForPool(address conicPool) external view returns (uint256);\n\n    function updateBoost(address user) external;\n\n    function claimCNCRewardsForPool(address pool) external;\n\n    function claimableCnc(address pool) external view returns (uint256);\n\n    function checkpoint(address pool) external returns (uint256);\n\n    function shutdown() external;\n\n    function getBoost(address user) external view returns (uint256);\n\n    function isShutdown() external view returns (bool);\n}\n"
      },
      "IBonding.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IBonding {\n    event CncStartPriceSet(uint256 startPrice);\n    event PriceIncreaseFactorSet(uint256 factor);\n    event MinBondingAmountSet(uint256 amount);\n    event Bonded(\n        address indexed account,\n        address indexed recipient,\n        uint256 lpTokenAmount,\n        uint256 cncReceived,\n        uint256 lockTime\n    );\n    event DebtPoolSet(address indexed pool);\n    event DebtPoolFeesClaimed(uint256 crvAmount, uint256 cvxAmount, uint256 cncAmount);\n    event StreamClaimed(address indexed account, uint256 amount);\n    event BondingStarted(uint256 amount, uint256 epochs);\n    event RemainingCNCRecovered(uint256 amount);\n\n    function startBonding() external;\n\n    function setCncStartPrice(uint256 _cncStartPrice) external;\n\n    function setCncPriceIncreaseFactor(uint256 _priceIncreaseFactor) external;\n\n    function setMinBondingAmount(uint256 _minBondingAmount) external;\n\n    function setDebtPool(address _debtPool) external;\n\n    function bondCncCrvUsd(\n        uint256 lpTokenAmount,\n        uint256 minCncReceived,\n        uint64 cncLockTime\n    ) external returns (uint256);\n\n    function recoverRemainingCNC() external;\n\n    function claimStream() external;\n\n    function claimFeesForDebtPool() external;\n\n    function streamCheckpoint() external;\n\n    function accountCheckpoint(address account) external;\n\n    function computeCurrentCncBondPrice() external view returns (uint256);\n\n    function cncAvailable() external view returns (uint256);\n\n    function cncBondPrice() external view returns (uint256);\n\n    function bondCncCrvUsdFor(\n        uint256 lpTokenAmount,\n        uint256 minCncReceived,\n        uint64 cncLockTime,\n        address recipient\n    ) external returns (uint256);\n}\n"
      },
      "IPoolAdapter.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IPoolAdapter {\n    /// @notice This is to set which LP token price the value computation should use\n    /// `Latest` uses a freshly computed price\n    /// `Cached` uses the price in cache\n    /// `Minimum` uses the minimum of these two\n    enum PriceMode {\n        Latest,\n        Cached,\n        Minimum\n    }\n\n    /// @notice Deposit `underlyingAmount` of `underlying` into `pool`\n    /// @dev This function should be written with the assumption that it will be delegate-called into\n    function deposit(address pool, address underlying, uint256 underlyingAmount) external;\n\n    /// @notice Withdraw `underlyingAmount` of `underlying` from `pool`\n    /// @dev This function should be written with the assumption that it will be delegate-called into\n    function withdraw(address pool, address underlying, uint256 underlyingAmount) external;\n\n    /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of USD\n    function computePoolValueInUSD(\n        address conicPool,\n        address pool\n    ) external view returns (uint256 usdAmount);\n\n    /// @notice Updates the price caches of the given pools\n    function updatePriceCache(address pool) external;\n\n    /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of USD\n    /// using the given price mode\n    function computePoolValueInUSD(\n        address conicPool,\n        address pool,\n        PriceMode priceMode\n    ) external view returns (uint256 usdAmount);\n\n    /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of underlying\n    function computePoolValueInUnderlying(\n        address conicPool,\n        address pool,\n        address underlying,\n        uint256 underlyingPrice\n    ) external view returns (uint256 underlyingAmount);\n\n    /// @notice Returns the amount of of assets that `conicPool` holds in `pool`, in terms of underlying\n    /// using the given price mode\n    function computePoolValueInUnderlying(\n        address conicPool,\n        address pool,\n        address underlying,\n        uint256 underlyingPrice,\n        PriceMode priceMode\n    ) external view returns (uint256 underlyingAmount);\n\n    /// @notice Claim earnings of `conicPool` from `pool`\n    function claimEarnings(address conicPool, address pool) external;\n\n    /// @notice Returns the LP token of a given `pool`\n    function lpToken(address pool) external view returns (address);\n\n    /// @notice Returns true if `pool` supports `asset`\n    function supportsAsset(address pool, address asset) external view returns (bool);\n\n    /// @notice Returns the amount of CRV earned by `pool` on Convex\n    function getCRVEarnedOnConvex(\n        address account,\n        address curvePool\n    ) external view returns (uint256);\n\n    /// @notice Executes a sanity check, e.g. checking for reentrancy\n    function executeSanityCheck(address pool) external;\n\n    /// @notice returns all the underlying coins of the pool\n    function getAllUnderlyingCoins(address pool) external view returns (address[] memory);\n}\n"
      },
      "IFeeRecipient.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\ninterface IFeeRecipient {\n    event FeesReceived(address indexed sender, uint256 crvAmount, uint256 cvxAmount);\n\n    function receiveFees(uint256 amountCrv, uint256 amountCvx) external;\n}\n"
      },
      "StringUtils.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.17;\n\nlibrary StringUtils {\n    uint256 internal constant _ASCII_0 = 48;\n\n    function extractMajorVersion(string memory version) internal pure returns (uint256) {\n        bytes memory versionBytes = bytes(version);\n        uint256 majorVersion = 0;\n        for (\n            uint256 i = versionBytes[0] == \"v\" ? 1 : 0;\n            i < versionBytes.length && versionBytes[i] != \".\";\n            i++\n        ) {\n            majorVersion = majorVersion * 10 + (uint256(uint8(versionBytes[i])) - _ASCII_0);\n        }\n        return majorVersion;\n    }\n}\n"
      }
    },
    "settings": {
      "evmVersion": "london",
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "libraries": {
        "CurveHandler.sol": {}
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}