creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/destinations/adapters/CurveV2FactoryCryptoAdapter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\n\nimport { ICurveStableSwapNG } from \"src/interfaces/external/curve/ICurveStableSwapNG.sol\";\nimport { ICryptoSwapPool, IPool } from \"src/interfaces/external/curve/ICryptoSwapPool.sol\";\nimport { IWETH9 } from \"src/interfaces/utils/IWETH9.sol\";\nimport { LibAdapter } from \"src/libs/LibAdapter.sol\";\nimport { Errors } from \"src/utils/Errors.sol\";\n\n//slither-disable-start similar-names\nlibrary CurveV2FactoryCryptoAdapter {\n    event WithdrawLiquidity(\n        uint256[] amountsWithdrawn,\n        address[] tokens,\n        // 0 - lpBurnAmount\n        // 1 - lpShare\n        // 2 - lpTotalSupply\n        uint256[3] lpAmounts,\n        address poolAddress\n    );\n\n    function removeLiquidity(\n        uint256[] memory amounts,\n        uint256 maxLpBurnAmount,\n        address poolAddress,\n        address lpTokenAddress,\n        IWETH9 weth\n    ) public returns (address[] memory, uint256[] memory) {\n        return removeLiquidity(amounts, maxLpBurnAmount, poolAddress, lpTokenAddress, weth, false);\n    }\n\n    /**\n     * @notice Withdraw liquidity from Curve pool\n     *  @dev Calls to external contract\n     *  @dev We trust sender to send a true Curve poolAddress.\n     *       If it's not the case it will fail in the remove_liquidity_one_coin part\n     *  @param amounts Minimum amounts of coin to receive\n     *  @param maxLpBurnAmount Amount of LP tokens to burn in the withdrawal\n     *  @param poolAddress Curve pool address\n     *  @param lpTokenAddress LP token of the pool to burn\n     *  @param weth WETH address on the operating chain\n     *  @param isNg is a newer ng pool with dynamic arrays\n     *  @return tokens Addresses of the withdrawn tokens\n     *  @return actualAmounts Amounts of the withdrawn tokens\n     */\n    function removeLiquidity(\n        uint256[] memory amounts,\n        uint256 maxLpBurnAmount,\n        address poolAddress,\n        address lpTokenAddress,\n        IWETH9 weth,\n        bool isNg\n    ) public returns (address[] memory tokens, uint256[] memory actualAmounts) {\n        //slither-disable-start reentrancy-events\n        if (amounts.length > 4) {\n            revert Errors.InvalidParam(\"amounts\");\n        }\n        Errors.verifyNotZero(maxLpBurnAmount, \"maxLpBurnAmount\");\n        Errors.verifyNotZero(poolAddress, \"poolAddress\");\n        Errors.verifyNotZero(lpTokenAddress, \"lpTokenAddress\");\n        Errors.verifyNotZero(address(weth), \"weth\");\n\n        uint256[] memory coinsBalancesBefore = new uint256[](amounts.length);\n        tokens = new address[](amounts.length);\n        uint256 ethIndex = 999;\n        for (uint256 i = 0; i < amounts.length; ++i) {\n            address coin = IPool(poolAddress).coins(i);\n            tokens[i] = coin;\n\n            if (coin == LibAdapter.CURVE_REGISTRY_ETH_ADDRESS_POINTER) {\n                coinsBalancesBefore[i] = address(this).balance;\n                ethIndex = i;\n            } else {\n                tokens[i] = coin;\n                coinsBalancesBefore[i] = IERC20(coin).balanceOf(address(this));\n            }\n        }\n        uint256 lpTokenBalanceBefore = IERC20(lpTokenAddress).balanceOf(address(this));\n\n        _runWithdrawal(poolAddress, amounts, maxLpBurnAmount, isNg);\n\n        uint256 lpTokenBalanceAfter = IERC20(lpTokenAddress).balanceOf(address(this));\n        uint256 lpTokenAmount = lpTokenBalanceBefore - lpTokenBalanceAfter;\n        if (lpTokenAmount > maxLpBurnAmount) {\n            revert LibAdapter.LpTokenAmountMismatch();\n        }\n        actualAmounts = _compareCoinsBalances(\n            coinsBalancesBefore, _getCoinsBalances(tokens, weth, ethIndex != 999 ? true : false), amounts, false\n        );\n\n        if (ethIndex != 999) {\n            // Wrapping up received ETH as system operates with WETH\n            // slither-disable-next-line arbitrary-send-eth\n            weth.deposit{ value: actualAmounts[ethIndex] }();\n        }\n\n        _updateWethAddress(tokens, address(weth));\n\n        emit WithdrawLiquidity(\n            actualAmounts,\n            tokens,\n            [lpTokenAmount, lpTokenBalanceAfter, IERC20(lpTokenAddress).totalSupply()],\n            poolAddress\n        );\n        //slither-disable-end reentrancy-events\n    }\n\n    /**\n     * @dev This is a helper function to replace Curve's Registry pointer\n     * to ETH with WETH address to be compatible with the rest of the system\n     */\n    function _updateWethAddress(address[] memory tokens, address weth) private pure {\n        for (uint256 i = 0; i < tokens.length; ++i) {\n            if (tokens[i] == LibAdapter.CURVE_REGISTRY_ETH_ADDRESS_POINTER) {\n                tokens[i] = weth;\n            }\n        }\n    }\n\n    /// @dev Gets balances of pool's ERC-20 tokens or ETH\n    function _getCoinsBalances(\n        address[] memory tokens,\n        IWETH9 weth,\n        bool useEth\n    ) private view returns (uint256[] memory coinsBalances) {\n        uint256 nTokens = tokens.length;\n        coinsBalances = new uint256[](nTokens);\n\n        for (uint256 i = 0; i < nTokens; ++i) {\n            address coin = tokens[i];\n            if (coin == LibAdapter.CURVE_REGISTRY_ETH_ADDRESS_POINTER) {\n                coinsBalances[i] = useEth ? address(this).balance : weth.balanceOf(address(this));\n            } else {\n                coinsBalances[i] = IERC20(coin).balanceOf(address(this));\n            }\n        }\n    }\n\n    /// @dev Validate to have a valid balance change\n    function _compareCoinsBalances(\n        uint256[] memory balancesBefore,\n        uint256[] memory balancesAfter,\n        uint256[] memory amounts,\n        bool isLiqDeployment\n    ) private pure returns (uint256[] memory balanceChange) {\n        uint256 nTokens = amounts.length;\n        balanceChange = new uint256[](nTokens);\n\n        for (uint256 i = 0; i < nTokens; ++i) {\n            uint256 balanceDiff =\n                isLiqDeployment ? balancesBefore[i] - balancesAfter[i] : balancesAfter[i] - balancesBefore[i];\n\n            if (balanceDiff < amounts[i]) {\n                revert LibAdapter.InvalidBalanceChange();\n            }\n            balanceChange[i] = balanceDiff;\n        }\n    }\n\n    function _runWithdrawal(\n        address poolAddress,\n        uint256[] memory amounts,\n        uint256 maxLpBurnAmount,\n        bool isNg\n    ) private {\n        if (isNg) {\n            ICurveStableSwapNG pool = ICurveStableSwapNG(poolAddress);\n\n            // slither-disable-next-line unused-return\n            pool.remove_liquidity(maxLpBurnAmount, amounts);\n        } else {\n            uint256 nTokens = amounts.length;\n            ICryptoSwapPool pool = ICryptoSwapPool(poolAddress);\n            if (nTokens == 2) {\n                uint256[2] memory staticParamArray = [amounts[0], amounts[1]];\n                pool.remove_liquidity(maxLpBurnAmount, staticParamArray);\n            } else if (nTokens == 3) {\n                uint256[3] memory staticParamArray = [amounts[0], amounts[1], amounts[2]];\n                pool.remove_liquidity(maxLpBurnAmount, staticParamArray);\n            } else if (nTokens == 4) {\n                uint256[4] memory staticParamArray = [amounts[0], amounts[1], amounts[2], amounts[3]];\n                pool.remove_liquidity(maxLpBurnAmount, staticParamArray);\n            }\n        }\n    }\n\n    //slither-disable-end similar-names\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "src/interfaces/external/curve/ICurveStableSwapNG.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\n// solhint-disable var-name-mixedcase,func-name-mixedcase\n\n/// @notice Interface for next generation Curve pool oracle functionality.\ninterface ICurveStableSwapNG {\n    /// @notice Returns current price in pool.\n    function price_oracle() external view returns (uint256);\n\n    function add_liquidity(uint256[] memory amounts, uint256 min_mint_amount) external payable returns (uint256);\n\n    function remove_liquidity(uint256 amount, uint256[] memory min_amounts) external returns (uint256[] memory);\n}\n"
      },
      "src/interfaces/external/curve/ICryptoSwapPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nimport { IPool } from \"src/interfaces/external/curve/IPool.sol\";\n\n/* solhint-disable func-name-mixedcase, var-name-mixedcase */\ninterface ICryptoSwapPool is IPool {\n    function token() external returns (address);\n\n    // slither-disable-start naming-convention\n    function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount) external payable returns (uint256);\n\n    function add_liquidity(uint256[3] memory amounts, uint256 min_mint_amount) external payable returns (uint256);\n\n    function add_liquidity(uint256[4] memory amounts, uint256 min_mint_amount) external payable returns (uint256);\n\n    function remove_liquidity(uint256 amount, uint256[2] memory min_amounts) external;\n\n    function remove_liquidity(uint256 amount, uint256[3] memory min_amounts) external;\n\n    function remove_liquidity(uint256 amount, uint256[4] memory min_amounts) external;\n\n    function remove_liquidity_one_coin(uint256 token_amount, uint256 i, uint256 min_amount) external;\n    // slither-disable-end naming-convention\n\n    function get_virtual_price() external returns (uint256);\n\n    function claim_admin_fees() external;\n}\n"
      },
      "src/interfaces/utils/IWETH9.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\n\ninterface IWETH9 is IERC20 {\n    function symbol() external view returns (string memory);\n\n    function deposit() external payable;\n    function withdraw(uint256 amount) external;\n}\n"
      },
      "src/libs/LibAdapter.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { IERC20 } from \"openzeppelin-contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol\";\n\nlibrary LibAdapter {\n    using SafeERC20 for IERC20;\n\n    address public constant CURVE_REGISTRY_ETH_ADDRESS_POINTER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n    error MinLpAmountNotReached();\n    error LpTokenAmountMismatch();\n    error NoNonZeroAmountProvided();\n    error InvalidBalanceChange();\n\n    // Utils\n    function _approve(IERC20 token, address spender, uint256 amount) internal {\n        uint256 currentAllowance = token.allowance(address(this), spender);\n        if (currentAllowance > 0) {\n            token.safeDecreaseAllowance(spender, currentAllowance);\n        }\n        token.safeIncreaseAllowance(spender, amount);\n    }\n}\n"
      },
      "src/utils/Errors.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\n// Copyright (c) 2023 Tokemak Foundation. All rights reserved.\npragma solidity 0.8.17;\n\nimport { Address } from \"openzeppelin-contracts/utils/Address.sol\";\n\nlibrary Errors {\n    using Address for address;\n    ///////////////////////////////////////////////////////////////////\n    //                       Set errors\n    ///////////////////////////////////////////////////////////////////\n\n    error AccessDenied();\n    error ZeroAddress(string paramName);\n    error ZeroAmount();\n    error InsufficientBalance(address token);\n    error AssetNotAllowed(address token);\n    error NotImplemented();\n    error InvalidAddress(address addr);\n    error InvalidParam(string paramName);\n    error InvalidParams();\n    error UnsafePrice(address token, uint256 spotPrice, uint256 safePrice);\n    error AlreadySet(string param);\n    error AlreadyRegistered(address param);\n    error SlippageExceeded(uint256 expected, uint256 actual);\n    error ArrayLengthMismatch(uint256 length1, uint256 length2, string details);\n\n    error ItemNotFound();\n    error ItemExists();\n    error MissingRole(bytes32 role, address user);\n    error RegistryItemMissing(string item);\n    error NotRegistered();\n    // Used to check storage slot is empty before setting.\n    error MustBeZero();\n    // Used to check storage slot set before deleting.\n    error MustBeSet();\n\n    error ApprovalFailed(address token);\n    error FlashLoanFailed(address token, uint256 amount);\n\n    error SystemMismatch(address source1, address source2);\n\n    error InvalidToken(address token);\n    error UnreachableError();\n\n    error InvalidSigner(address signer);\n\n    error InvalidChainId(uint256 chainId);\n\n    error SenderMismatch(address recipient, address sender);\n\n    function verifyNotZero(address addr, string memory paramName) internal pure {\n        if (addr == address(0)) {\n            revert ZeroAddress(paramName);\n        }\n    }\n\n    function verifyNotZero(bytes32 key, string memory paramName) internal pure {\n        if (key == bytes32(0)) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifyNotEmpty(string memory val, string memory paramName) internal pure {\n        if (bytes(val).length == 0) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifyNotZero(uint256 num, string memory paramName) internal pure {\n        if (num == 0) {\n            revert InvalidParam(paramName);\n        }\n    }\n\n    function verifySystemsMatch(address component1, address component2) internal view {\n        bytes memory call = abi.encodeWithSignature(\"getSystemRegistry()\");\n\n        address registry1 = abi.decode(component1.functionStaticCall(call), (address));\n        address registry2 = abi.decode(component2.functionStaticCall(call), (address));\n\n        if (registry1 != registry2) {\n            revert SystemMismatch(component1, component2);\n        }\n    }\n\n    function verifyArrayLengths(uint256 length1, uint256 length2, string memory details) internal pure {\n        if (length1 != length2) {\n            revert ArrayLengthMismatch(length1, length2, details);\n        }\n    }\n}\n"
      },
      "src/interfaces/external/curve/IPool.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\n//slither-disable-next-line name-reused\ninterface IPool {\n    function coins(uint256 i) external view returns (address);\n\n    function balances(uint256 i) external view returns (uint256);\n\n    // These method used for cases when Pool is a LP token at the same time\n    function balanceOf(address account) external returns (uint256);\n\n    // These method used for cases when Pool is a LP token at the same time\n    function totalSupply() external returns (uint256);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/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    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) 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(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) 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    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\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        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.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     *\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://diligence.consensys.net/posts/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.5.11/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(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) 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"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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"
      }
    },
    "settings": {
      "remappings": [
        "forge-std/=lib/forge-std/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "src/=src/",
        "test/=test/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
        "erc4626-tests/=lib/erc4626-tests/",
        "prb-math/=lib/prb-math/",
        "crytic/properties/=lib/properties/",
        "ERC4626/=lib/properties/lib/ERC4626/contracts/",
        "properties/=lib/properties/contracts/",
        "solmate/=lib/properties/lib/solmate/src/",
        "usingtellor/=lib/usingtellor/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs"
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "london",
      "viaIR": false,
      "libraries": {
        "src/destinations/adapters/CurveV2FactoryCryptoAdapter.sol": {
          "CurveV2FactoryCryptoAdapter": "0xe46E7634d6e0BC954407078818fF62eDfF414184"
        },
        "src/destinations/adapters/rewards/ConvexRewardsAdapter.sol": {
          "ConvexRewards": "0x08F295fD04B52Ab6a7f8A86bC9A0A1c0EA8aDE01"
        },
        "src/destinations/adapters/staking/ConvexAdapter.sol": {
          "ConvexStaking": "0x6c2f91978004B0A769c622dfe352EdF331044d49"
        }
      }
    }
  }}