creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/strategies/YearnGaugeStrategy.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.18;\n\nimport { BaseStrategy } from \"tokenized-strategy/BaseStrategy.sol\";\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { CurveRouterSwapper } from \"src/swappers/CurveRouterSwapper.sol\";\nimport { YearnGaugeStrategyBase } from \"./YearnGaugeStrategyBase.sol\";\nimport { IYearnStakingDelegate } from \"src/interfaces/IYearnStakingDelegate.sol\";\nimport { Errors } from \"src/libraries/Errors.sol\";\n\n/**\n * @title YearnGaugeStrategy\n * @notice Strategy for interacting with Yearn Gauge\n */\ncontract YearnGaugeStrategy is BaseStrategy, CurveRouterSwapper, YearnGaugeStrategyBase {\n    // Libraries\n    using SafeERC20 for IERC20;\n\n    /// @notice Parameters for Curve swap used during harvest\n    CurveSwapParams internal _harvestSwapParams;\n\n    /// @notice Address of the contract that will be redeeming dYFI for YFI for this strategy\n    address private _dYfiRedeemer;\n\n    //// events ////\n    event DYfiRedeemerSet(address oldDYfiRedeemer, address newDYfiRedeemer);\n\n    /**\n     * @notice Initializes the YearnGaugeStrategy\n     * @param asset_ The address of the asset (gauge token)\n     * @param yearnStakingDelegate_ The address of the YearnStakingDelegate\n     * @param curveRouter_ The address of the Curve router\n     */\n    constructor(\n        address asset_,\n        address yearnStakingDelegate_,\n        address curveRouter_\n    )\n        payable\n        BaseStrategy(asset_, \"Wrapped YearnV3 Strategy\")\n        CurveRouterSwapper(curveRouter_)\n        YearnGaugeStrategyBase(asset_, yearnStakingDelegate_)\n    {\n        _approveTokenForSwap(_YFI);\n    }\n\n    /**\n     * @notice Sets the parameters for the Curve swap used in the harvest function\n     * @param curveSwapParams The parameters for the Curve swap\n     */\n    function setHarvestSwapParams(CurveSwapParams calldata curveSwapParams) external onlyManagement {\n        // Checks (includes external view calls)\n        _validateSwapParams(curveSwapParams, _YFI, _VAULT_ASSET);\n\n        // Effects\n        _harvestSwapParams = curveSwapParams;\n    }\n\n    /**\n     * @notice Sets the address of the contract that will be redeeming dYFI\n     * @param newDYfiRedeemer The address of the new dYFI redeemer contract\n     */\n    function setDYfiRedeemer(address newDYfiRedeemer) external onlyManagement {\n        // Checks\n        if (newDYfiRedeemer == address(0)) {\n            revert Errors.ZeroAddress();\n        }\n        address currentDYfiRedeemer = _dYfiRedeemer;\n        if (newDYfiRedeemer == currentDYfiRedeemer) {\n            revert Errors.SameAddress();\n        }\n        // Effects\n        _dYfiRedeemer = newDYfiRedeemer;\n        // Interactions\n        emit DYfiRedeemerSet(currentDYfiRedeemer, newDYfiRedeemer);\n        if (currentDYfiRedeemer != address(0)) {\n            IERC20(_DYFI).forceApprove(currentDYfiRedeemer, 0);\n        }\n        IERC20(_DYFI).forceApprove(newDYfiRedeemer, type(uint256).max);\n    }\n\n    /**\n     * @notice Get the address of the contract that will be redeeming dYFI from this strategy\n     * @return The address of the dYFI redeemer contract\n     */\n    function dYfiRedeemer() external view returns (address) {\n        return _dYfiRedeemer;\n    }\n\n    /**\n     * @notice Calculates the available deposit limit for the strategy\n     * @return The strategy's available deposit limit\n     */\n    function availableDepositLimit(address) public view override returns (uint256) {\n        return IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).availableDepositLimit(address(asset));\n    }\n\n    /**\n     * @dev Deploys funds into the YearnStakingDelegate by depositing the asset.\n     * @param _amount The amount of the asset to deposit.\n     */\n    function _deployFunds(uint256 _amount) internal override {\n        _depositToYSD(address(asset), _amount);\n    }\n\n    /**\n     * @dev Withdraws funds from the YearnStakingDelegate by withdrawing the asset.\n     * @param _amount The amount of the asset to withdraw.\n     */\n    function _freeFunds(uint256 _amount) internal override {\n        _withdrawFromYSD(address(asset), _amount);\n    }\n\n    /**\n     * @dev Performs an emergency withdrawal from the YearnStakingDelegate, withdrawing the asset to the strategy.\n     * @param amount The amount to withdraw in case of an emergency.\n     */\n    function _emergencyWithdraw(uint256 amount) internal override {\n        uint256 deployedAmount = depositedInYSD(address(asset));\n        uint256 withdrawAmount = amount > deployedAmount ? deployedAmount : amount;\n        _withdrawFromYSD(address(asset), withdrawAmount);\n    }\n\n    /**\n     * @notice Harvests dYfi rewards, swaps YFI for the vault asset, and re-deposits or adds to idle balance\n     * @return _totalAssets The total assets after harvest and redeposit/idle balance update\n     */\n    function _harvestAndReport() internal override returns (uint256 _totalAssets) {\n        // Check for any dYfi that has been redeemed for Yfi\n        uint256 yfiBalance = IERC20(_YFI).balanceOf(address(this));\n        // If dfi has been redeemed for Yfi, swap it for vault asset and deploy it to the strategy\n        if (yfiBalance > 0) {\n            // This is a dangerous swap call that will get sandwiched if sent to a public network\n            // Must be sent to a private network or use a minAmount derived from a price oracle\n            uint256 receivedBaseTokens = _swap(_harvestSwapParams, yfiBalance, 0, address(this));\n            uint256 receivedVaultTokens = IERC4626(_VAULT).deposit(receivedBaseTokens, address(this));\n            uint256 receivedGaugeTokens = IERC4626(address(asset)).deposit(receivedVaultTokens, address(this));\n\n            // If the strategy is not shutdown, deploy the funds\n            // Else add the received tokens to the idle balance\n            if (!TokenizedStrategy.isShutdown()) {\n                _deployFunds(receivedGaugeTokens);\n            }\n        }\n        // Return the total idle assets and the deployed assets\n        return asset.balanceOf(address(this)) + depositedInYSD(address(asset));\n    }\n}\n"
      },
      "lib/tokenized-strategy/src/BaseStrategy.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity 0.8.18;\n\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n// TokenizedStrategy interface used for internal view delegateCalls.\nimport {ITokenizedStrategy} from \"./interfaces/ITokenizedStrategy.sol\";\n\n/**\n * @title YearnV3 Base Strategy\n * @author yearn.finance\n * @notice\n *  BaseStrategy implements all of the required functionality to\n *  seamlessly integrate with the `TokenizedStrategy` implementation contract\n *  allowing anyone to easily build a fully permissionless ERC-4626 compliant\n *  Vault by inheriting this contract and overriding three simple functions.\n\n *  It utilizes an immutable proxy pattern that allows the BaseStrategy\n *  to remain simple and small. All standard logic is held within the\n *  `TokenizedStrategy` and is reused over any n strategies all using the\n *  `fallback` function to delegatecall the implementation so that strategists\n *  can only be concerned with writing their strategy specific code.\n *\n *  This contract should be inherited and the three main abstract methods\n *  `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt\n *  the Strategy to the particular needs it has to generate yield. There are\n *  other optional methods that can be implemented to further customize\n *  the strategy if desired.\n *\n *  All default storage for the strategy is controlled and updated by the\n *  `TokenizedStrategy`. The implementation holds a storage struct that\n *  contains all needed global variables in a manual storage slot. This\n *  means strategists can feel free to implement their own custom storage\n *  variables as they need with no concern of collisions. All global variables\n *  can be viewed within the Strategy by a simple call using the\n *  `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();.\n */\nabstract contract BaseStrategy {\n    /*//////////////////////////////////////////////////////////////\n                            MODIFIERS\n    //////////////////////////////////////////////////////////////*/\n    /**\n     * @dev Used on TokenizedStrategy callback functions to make sure it is post\n     * a delegateCall from this address to the TokenizedStrategy.\n     */\n    modifier onlySelf() {\n        _onlySelf();\n        _;\n    }\n\n    /**\n     * @dev Use to assure that the call is coming from the strategies management.\n     */\n    modifier onlyManagement() {\n        TokenizedStrategy.requireManagement(msg.sender);\n        _;\n    }\n\n    /**\n     * @dev Use to assure that the call is coming from either the strategies\n     * management or the keeper.\n     */\n    modifier onlyKeepers() {\n        TokenizedStrategy.requireKeeperOrManagement(msg.sender);\n        _;\n    }\n\n    /**\n     * @dev Use to assure that the call is coming from either the strategies\n     * management or the emergency admin.\n     */\n    modifier onlyEmergencyAuthorized() {\n        TokenizedStrategy.requireEmergencyAuthorized(msg.sender);\n        _;\n    }\n\n    /**\n     * @dev Require that the msg.sender is this address.\n     */\n    function _onlySelf() internal view {\n        require(msg.sender == address(this), \"!self\");\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    /**\n     * @dev This is the address of the TokenizedStrategy implementation\n     * contract that will be used by all strategies to handle the\n     * accounting, logic, storage etc.\n     *\n     * Any external calls to the that don't hit one of the functions\n     * defined in this base or the strategy will end up being forwarded\n     * through the fallback function, which will delegateCall this address.\n     *\n     * This address should be the same for every strategy, never be adjusted\n     * and always be checked before any integration with the Strategy.\n     */\n    address public constant tokenizedStrategyAddress =\n        0xBB51273D6c746910C7C06fe718f30c936170feD0;\n\n    /*//////////////////////////////////////////////////////////////\n                            IMMUTABLES\n    //////////////////////////////////////////////////////////////*/\n\n    /**\n     * @dev Underlying asset the Strategy is earning yield on.\n     * Stored here for cheap retrievals within the strategy.\n     */\n    ERC20 internal immutable asset;\n\n    /**\n     * @dev This variable is set to address(this) during initialization of each strategy.\n     *\n     * This can be used to retrieve storage data within the strategy\n     * contract as if it were a linked library.\n     *\n     *       i.e. uint256 totalAssets = TokenizedStrategy.totalAssets()\n     *\n     * Using address(this) will mean any calls using this variable will lead\n     * to a call to itself. Which will hit the fallback function and\n     * delegateCall that to the actual TokenizedStrategy.\n     */\n    ITokenizedStrategy internal immutable TokenizedStrategy;\n\n    /**\n     * @notice Used to initialize the strategy on deployment.\n     *\n     * This will set the `TokenizedStrategy` variable for easy\n     * internal view calls to the implementation. As well as\n     * initializing the default storage variables based on the\n     * parameters and using the deployer for the permissioned roles.\n     *\n     * @param _asset Address of the underlying asset.\n     * @param _name Name the strategy will use.\n     */\n    constructor(address _asset, string memory _name) {\n        asset = ERC20(_asset);\n\n        // Set instance of the implementation for internal use.\n        TokenizedStrategy = ITokenizedStrategy(address(this));\n\n        // Initialize the strategy's storage variables.\n        _delegateCall(\n            abi.encodeCall(\n                ITokenizedStrategy.initialize,\n                (_asset, _name, msg.sender, msg.sender, msg.sender)\n            )\n        );\n\n        // Store the tokenizedStrategyAddress at the standard implementation\n        // address storage slot so etherscan picks up the interface. This gets\n        // stored on initialization and never updated.\n        assembly {\n            sstore(\n                // keccak256('eip1967.proxy.implementation' - 1)\n                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,\n                tokenizedStrategyAddress\n            )\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                NEEDED TO BE OVERRIDDEN BY STRATEGIST\n    //////////////////////////////////////////////////////////////*/\n\n    /**\n     * @dev Can deploy up to '_amount' of 'asset' in the yield source.\n     *\n     * This function is called at the end of a {deposit} or {mint}\n     * call. Meaning that unless a whitelist is implemented it will\n     * be entirely permissionless and thus can be sandwiched or otherwise\n     * manipulated.\n     *\n     * @param _amount The amount of 'asset' that the strategy can attempt\n     * to deposit in the yield source.\n     */\n    function _deployFunds(uint256 _amount) internal virtual;\n\n    /**\n     * @dev Should attempt to free the '_amount' of 'asset'.\n     *\n     * NOTE: The amount of 'asset' that is already loose has already\n     * been accounted for.\n     *\n     * This function is called during {withdraw} and {redeem} calls.\n     * Meaning that unless a whitelist is implemented it will be\n     * entirely permissionless and thus can be sandwiched or otherwise\n     * manipulated.\n     *\n     * Should not rely on asset.balanceOf(address(this)) calls other than\n     * for diff accounting purposes.\n     *\n     * Any difference between `_amount` and what is actually freed will be\n     * counted as a loss and passed on to the withdrawer. This means\n     * care should be taken in times of illiquidity. It may be better to revert\n     * if withdraws are simply illiquid so not to realize incorrect losses.\n     *\n     * @param _amount, The amount of 'asset' to be freed.\n     */\n    function _freeFunds(uint256 _amount) internal virtual;\n\n    /**\n     * @dev Internal function to harvest all rewards, redeploy any idle\n     * funds and return an accurate accounting of all funds currently\n     * held by the Strategy.\n     *\n     * This should do any needed harvesting, rewards selling, accrual,\n     * redepositing etc. to get the most accurate view of current assets.\n     *\n     * NOTE: All applicable assets including loose assets should be\n     * accounted for in this function.\n     *\n     * Care should be taken when relying on oracles or swap values rather\n     * than actual amounts as all Strategy profit/loss accounting will\n     * be done based on this returned value.\n     *\n     * This can still be called post a shutdown, a strategist can check\n     * `TokenizedStrategy.isShutdown()` to decide if funds should be\n     * redeployed or simply realize any profits/losses.\n     *\n     * @return _totalAssets A trusted and accurate account for the total\n     * amount of 'asset' the strategy currently holds including idle funds.\n     */\n    function _harvestAndReport()\n        internal\n        virtual\n        returns (uint256 _totalAssets);\n\n    /*//////////////////////////////////////////////////////////////\n                    OPTIONAL TO OVERRIDE BY STRATEGIST\n    //////////////////////////////////////////////////////////////*/\n\n    /**\n     * @dev Optional function for strategist to override that can\n     *  be called in between reports.\n     *\n     * If '_tend' is used tendTrigger() will also need to be overridden.\n     *\n     * This call can only be called by a permissioned role so may be\n     * through protected relays.\n     *\n     * This can be used to harvest and compound rewards, deposit idle funds,\n     * perform needed position maintenance or anything else that doesn't need\n     * a full report for.\n     *\n     *   EX: A strategy that can not deposit funds without getting\n     *       sandwiched can use the tend when a certain threshold\n     *       of idle to totalAssets has been reached.\n     *\n     * This will have no effect on PPS of the strategy till report() is called.\n     *\n     * @param _totalIdle The current amount of idle funds that are available to deploy.\n     */\n    function _tend(uint256 _totalIdle) internal virtual {}\n\n    /**\n     * @dev Optional trigger to override if tend() will be used by the strategy.\n     * This must be implemented if the strategy hopes to invoke _tend().\n     *\n     * @return . Should return true if tend() should be called by keeper or false if not.\n     */\n    function _tendTrigger() internal view virtual returns (bool) {\n        return false;\n    }\n\n    /**\n     * @notice Returns if tend() should be called by a keeper.\n     *\n     * @return . Should return true if tend() should be called by keeper or false if not.\n     * @return . Calldata for the tend call.\n     */\n    function tendTrigger() external view virtual returns (bool, bytes memory) {\n        return (\n            // Return the status of the tend trigger.\n            _tendTrigger(),\n            // And the needed calldata either way.\n            abi.encodeWithSelector(ITokenizedStrategy.tend.selector)\n        );\n    }\n\n    /**\n     * @notice Gets the max amount of `asset` that an address can deposit.\n     * @dev Defaults to an unlimited amount for any address. But can\n     * be overridden by strategists.\n     *\n     * This function will be called before any deposit or mints to enforce\n     * any limits desired by the strategist. This can be used for either a\n     * traditional deposit limit or for implementing a whitelist etc.\n     *\n     *   EX:\n     *      if(isAllowed[_owner]) return super.availableDepositLimit(_owner);\n     *\n     * This does not need to take into account any conversion rates\n     * from shares to assets. But should know that any non max uint256\n     * amounts may be converted to shares. So it is recommended to keep\n     * custom amounts low enough as not to cause overflow when multiplied\n     * by `totalSupply`.\n     *\n     * @param . The address that is depositing into the strategy.\n     * @return . The available amount the `_owner` can deposit in terms of `asset`\n     */\n    function availableDepositLimit(\n        address /*_owner*/\n    ) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /**\n     * @notice Gets the max amount of `asset` that can be withdrawn.\n     * @dev Defaults to an unlimited amount for any address. But can\n     * be overridden by strategists.\n     *\n     * This function will be called before any withdraw or redeem to enforce\n     * any limits desired by the strategist. This can be used for illiquid\n     * or sandwichable strategies. It should never be lower than `totalIdle`.\n     *\n     *   EX:\n     *       return TokenIzedStrategy.totalIdle();\n     *\n     * This does not need to take into account the `_owner`'s share balance\n     * or conversion rates from shares to assets.\n     *\n     * @param . The address that is withdrawing from the strategy.\n     * @return . The available amount that can be withdrawn in terms of `asset`\n     */\n    function availableWithdrawLimit(\n        address /*_owner*/\n    ) public view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /**\n     * @dev Optional function for a strategist to override that will\n     * allow management to manually withdraw deployed funds from the\n     * yield source if a strategy is shutdown.\n     *\n     * This should attempt to free `_amount`, noting that `_amount` may\n     * be more than is currently deployed.\n     *\n     * NOTE: This will not realize any profits or losses. A separate\n     * {report} will be needed in order to record any profit/loss. If\n     * a report may need to be called after a shutdown it is important\n     * to check if the strategy is shutdown during {_harvestAndReport}\n     * so that it does not simply re-deploy all funds that had been freed.\n     *\n     * EX:\n     *   if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {\n     *       depositFunds...\n     *    }\n     *\n     * @param _amount The amount of asset to attempt to free.\n     */\n    function _emergencyWithdraw(uint256 _amount) internal virtual {}\n\n    /*//////////////////////////////////////////////////////////////\n                        TokenizedStrategy HOOKS\n    //////////////////////////////////////////////////////////////*/\n\n    /**\n     * @notice Can deploy up to '_amount' of 'asset' in yield source.\n     * @dev Callback for the TokenizedStrategy to call during a {deposit}\n     * or {mint} to tell the strategy it can deploy funds.\n     *\n     * Since this can only be called after a {deposit} or {mint}\n     * delegateCall to the TokenizedStrategy msg.sender == address(this).\n     *\n     * Unless a whitelist is implemented this will be entirely permissionless\n     * and thus can be sandwiched or otherwise manipulated.\n     *\n     * @param _amount The amount of 'asset' that the strategy can\n     * attempt to deposit in the yield source.\n     */\n    function deployFunds(uint256 _amount) external virtual onlySelf {\n        _deployFunds(_amount);\n    }\n\n    /**\n     * @notice Should attempt to free the '_amount' of 'asset'.\n     * @dev Callback for the TokenizedStrategy to call during a withdraw\n     * or redeem to free the needed funds to service the withdraw.\n     *\n     * This can only be called after a 'withdraw' or 'redeem' delegateCall\n     * to the TokenizedStrategy so msg.sender == address(this).\n     *\n     * @param _amount The amount of 'asset' that the strategy should attempt to free up.\n     */\n    function freeFunds(uint256 _amount) external virtual onlySelf {\n        _freeFunds(_amount);\n    }\n\n    /**\n     * @notice Returns the accurate amount of all funds currently\n     * held by the Strategy.\n     * @dev Callback for the TokenizedStrategy to call during a report to\n     * get an accurate accounting of assets the strategy controls.\n     *\n     * This can only be called after a report() delegateCall to the\n     * TokenizedStrategy so msg.sender == address(this).\n     *\n     * @return . A trusted and accurate account for the total amount\n     * of 'asset' the strategy currently holds including idle funds.\n     */\n    function harvestAndReport() external virtual onlySelf returns (uint256) {\n        return _harvestAndReport();\n    }\n\n    /**\n     * @notice Will call the internal '_tend' when a keeper tends the strategy.\n     * @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy.\n     *\n     * This can only be called after a tend() delegateCall to the TokenizedStrategy\n     * so msg.sender == address(this).\n     *\n     * We name the function `tendThis` so that `tend` calls are forwarded to\n     * the TokenizedStrategy.\n\n     * @param _totalIdle The amount of current idle funds that can be\n     * deployed during the tend\n     */\n    function tendThis(uint256 _totalIdle) external virtual onlySelf {\n        _tend(_totalIdle);\n    }\n\n    /**\n     * @notice Will call the internal '_emergencyWithdraw' function.\n     * @dev Callback for the TokenizedStrategy during an emergency withdraw.\n     *\n     * This can only be called after a emergencyWithdraw() delegateCall to\n     * the TokenizedStrategy so msg.sender == address(this).\n     *\n     * We name the function `shutdownWithdraw` so that `emergencyWithdraw`\n     * calls are forwarded to the TokenizedStrategy.\n     *\n     * @param _amount The amount of asset to attempt to free.\n     */\n    function shutdownWithdraw(uint256 _amount) external virtual onlySelf {\n        _emergencyWithdraw(_amount);\n    }\n\n    /**\n     * @dev Function used to delegate call the TokenizedStrategy with\n     * certain `_calldata` and return any return values.\n     *\n     * This is used to setup the initial storage of the strategy, and\n     * can be used by strategist to forward any other call to the\n     * TokenizedStrategy implementation.\n     *\n     * @param _calldata The abi encoded calldata to use in delegatecall.\n     * @return . The return value if the call was successful in bytes.\n     */\n    function _delegateCall(\n        bytes memory _calldata\n    ) internal returns (bytes memory) {\n        // Delegate call the tokenized strategy with provided calldata.\n        (bool success, bytes memory result) = tokenizedStrategyAddress\n            .delegatecall(_calldata);\n\n        // If the call reverted. Return the error.\n        if (!success) {\n            assembly {\n                let ptr := mload(0x40)\n                let size := returndatasize()\n                returndatacopy(ptr, 0, size)\n                revert(ptr, size)\n            }\n        }\n\n        // Return the result.\n        return result;\n    }\n\n    /**\n     * @dev Execute a function on the TokenizedStrategy and return any value.\n     *\n     * This fallback function will be executed when any of the standard functions\n     * defined in the TokenizedStrategy are called since they wont be defined in\n     * this contract.\n     *\n     * It will delegatecall the TokenizedStrategy implementation with the exact\n     * calldata and return any relevant values.\n     *\n     */\n    fallback() external {\n        // load our target address\n        address _tokenizedStrategyAddress = tokenizedStrategyAddress;\n        // Execute external function using delegatecall and return any value.\n        assembly {\n            // Copy function selector and any arguments.\n            calldatacopy(0, 0, calldatasize())\n            // Execute function delegatecall.\n            let result := delegatecall(\n                gas(),\n                _tokenizedStrategyAddress,\n                0,\n                calldatasize(),\n                0,\n                0\n            )\n            // Get any return value\n            returndatacopy(0, 0, returndatasize())\n            // Return any return value or error back to the caller\n            switch result\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/utils/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 \"../extensions/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    /**\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"
      },
      "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"
      },
      "src/swappers/CurveRouterSwapper.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.18;\n\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Errors } from \"src/libraries/Errors.sol\";\nimport { ICurveRouter } from \"src/interfaces/deps/curve/ICurveRouter.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @title Curve Router Library\n * @notice Contains helper methods for interacting with Curve Router.\n * @dev Curve router is deployed on these networks at 0xF0d4c12A5768D806021F80a262B4d39d26C58b8D\n * - Ethereum\n * - Optimism\n * - Gnosis\n * - Polygon\n * - Fantom\n * - Kava\n * - Arbitrum\n * - Avalanche\n * - Base at 0xd6681e74eEA20d196c15038C580f721EF2aB6320\n * https://github.com/curvefi/curve-router-ng/tree/master\n */\ncontract CurveRouterSwapper {\n    using SafeERC20 for IERC20;\n\n    /// @notice The address of the Curve Router contract\n    // solhint-disable-next-line var-name-mixedcase\n    // slither-disable-next-line naming-convention\n    address private immutable _CURVE_ROUTER;\n\n    /// @notice Struct to store parameters for a Curve swap\n    struct CurveSwapParams {\n        address[11] route;\n        uint256[5][5] swapParams;\n        address[5] pools;\n    }\n\n    /**\n     * @dev Sets the Curve Router address on contract deployment.\n     * @param curveRouter_ The address of the Curve Router.\n     */\n    constructor(address curveRouter_) payable {\n        // Checks\n        if (curveRouter_ == address(0)) {\n            revert Errors.ZeroAddress();\n        }\n        // Effects\n        _CURVE_ROUTER = curveRouter_;\n    }\n\n    /**\n     * @dev Approves the Curve Router to spend the specified token.\n     * @param token The ERC20 token address to approve.\n     */\n    function _approveTokenForSwap(address token) internal {\n        IERC20(token).forceApprove(_CURVE_ROUTER, type(uint256).max);\n    }\n\n    /**\n     * @dev Executes a token swap via the Curve Router.\n     * @param curveSwapParams The parameters for the swap.\n     * @param amount The amount of the input token to swap.\n     * @param expected The minimum amount of the output token expected to receive.\n     * @param receiver The address that will receive the output tokens.\n     * @return The amount of the output token received from the swap.\n     */\n    function _swap(\n        CurveSwapParams memory curveSwapParams,\n        uint256 amount,\n        uint256 expected,\n        address receiver\n    )\n        internal\n        returns (uint256)\n    {\n        return ICurveRouter(_CURVE_ROUTER).exchange(\n            curveSwapParams.route, curveSwapParams.swapParams, amount, expected, curveSwapParams.pools, receiver\n        );\n    }\n\n    /**\n     * @dev Validates the swap parameters against the provided route and tokens.\n     * @param curveSwapParams The parameters for the swap.\n     * @param fromToken The address of the input token.\n     * @param toToken The address of the output token.\n     */\n    function _validateSwapParams(\n        CurveSwapParams memory curveSwapParams,\n        address fromToken,\n        address toToken\n    )\n        internal\n        view\n    {\n        // Check if fromToken is in the route\n        if (fromToken != curveSwapParams.route[0]) {\n            revert Errors.InvalidFromToken(fromToken, curveSwapParams.route[0]);\n        }\n        // Check if toToken is in the route\n        address toTokenInRoute = address(0);\n        uint256 routeLength = curveSwapParams.route.length;\n        for (uint256 i = 0; i < routeLength;) {\n            if (curveSwapParams.route[i] == address(0)) {\n                break;\n            }\n            toTokenInRoute = curveSwapParams.route[i];\n\n            /// @dev The unchecked block is used here because the loop index `i` is simply incremented in each\n            /// iteration, ensuring that `i` will not exceed the length of the array and cause an overflow. Underflow is\n            /// not a concern as `i` is initialized to 0 and only incremented.\n            unchecked {\n                ++i;\n            }\n        }\n        if (toTokenInRoute != toToken) {\n            revert Errors.InvalidToToken(toToken, toTokenInRoute);\n        }\n        // Note that this does not check whether supplied token exists in the pool since the\n        // get_dy function only relies on the indexes on swaps instead of addresses.\n        try ICurveRouter(_CURVE_ROUTER).get_dy(\n            curveSwapParams.route,\n            curveSwapParams.swapParams,\n            10 ** IERC20Metadata(fromToken).decimals(),\n            curveSwapParams.pools\n        ) returns (uint256 expected) {\n            if (expected == 0) {\n                revert Errors.ExpectedAmountZero();\n            }\n        } catch {\n            revert Errors.InvalidSwapParams();\n        }\n    }\n}\n"
      },
      "src/strategies/YearnGaugeStrategyBase.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.18;\n\nimport { IYearnStakingDelegate } from \"src/interfaces/IYearnStakingDelegate.sol\";\nimport { Errors } from \"src/libraries/Errors.sol\";\nimport { SafeERC20, IERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport { IYearnVaultV2 } from \"src/interfaces/deps/yearn/veYFI/IYearnVaultV2.sol\";\n\n/**\n * @title YearnGaugeStrategyBase\n * @notice Abstract base contract for Yearn gauge strategies, handling deposits and withdrawals to the\n * YearnStakingDelegate.\n */\nabstract contract YearnGaugeStrategyBase {\n    // Libraries\n    using SafeERC20 for IERC20;\n\n    // Constant storage variables\n    // solhint-disable const-name-snakecase\n    /// @notice Address of the dYFI token\n    address internal constant _DYFI = 0x41252E8691e964f7DE35156B68493bAb6797a275;\n    /// @notice Address of the YFI token\n    address internal constant _YFI = 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e;\n    // solhint-enable const-name-snakecase\n\n    // Immutable storage variables\n    // solhint-disable immutable-vars-naming\n    // slither-disable-start naming-convention\n    /// @notice Address of the YearnStakingDelegate contract\n    address internal immutable _YEARN_STAKING_DELEGATE;\n    /// @notice Address of the vault's underlying asset\n    address internal immutable _VAULT_ASSET;\n    /// @notice Address of the Yearn vault\n    address internal immutable _VAULT;\n    // solhint-enable immutable-vars-naming\n    // slither-disable-end naming-convention\n\n    /**\n     * @dev Sets the initial configuration of the strategy and approves the maximum amount of tokens to the\n     * YearnStakingDelegate.\n     * @param asset_ The address of the asset (gauge token).\n     * @param yearnStakingDelegate_ The address of the Yearn Staking Delegate.\n     */\n    constructor(address asset_, address yearnStakingDelegate_) {\n        address vault_ = IERC4626(asset_).asset();\n        address vaultAsset_ = address(0);\n        try IERC4626(vault_).asset() returns (address returnedVaultAsset) {\n            vaultAsset_ = returnedVaultAsset;\n        } catch {\n            vaultAsset_ = IYearnVaultV2(vault_).token();\n        }\n        // Check for zero addresses\n        if (yearnStakingDelegate_ == address(0) || vault_ == address(0) || vaultAsset_ == address(0)) {\n            revert Errors.ZeroAddress();\n        }\n\n        // Effects\n        // Set storage variable values\n        _YEARN_STAKING_DELEGATE = yearnStakingDelegate_;\n        _VAULT = vault_;\n        _VAULT_ASSET = vaultAsset_;\n\n        // Interactions\n        IERC20(asset_).forceApprove(yearnStakingDelegate_, type(uint256).max);\n        IERC20(vaultAsset_).forceApprove(vault_, type(uint256).max);\n        IERC20(vault_).forceApprove(asset_, type(uint256).max);\n    }\n\n    /**\n     * @notice Get the address of the YearnStakingDelegate.\n     * @return The address of the YearnStakingDelegate.\n     */\n    function yearnStakingDelegate() external view returns (address) {\n        return _YEARN_STAKING_DELEGATE;\n    }\n\n    /**\n     * @notice Get the address of the vault's underlying asset. This is the asset that is deposited into the\n     * vault which then is deposited into the gauge.\n     * @return The address of the vault's underlying asset.\n     */\n    function vaultAsset() external view returns (address) {\n        return _VAULT_ASSET;\n    }\n\n    /**\n     * @notice Get the address of the vault. This is the Yearn vault that the gauge is for.\n     * @return The address of the vault.\n     */\n    function vault() external view returns (address) {\n        return _VAULT;\n    }\n\n    /**\n     * @dev Internal function to deposit assets into the YearnStakingDelegate.\n     * @param asset The address of the asset to deposit.\n     * @param amount The amount of the asset to deposit.\n     */\n    function _depositToYSD(address asset, uint256 amount) internal virtual {\n        IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).deposit(asset, amount);\n    }\n\n    /**\n     * @dev Internal function to withdraw assets from the YearnStakingDelegate.\n     * @param asset The address of the asset to withdraw.\n     * @param amount The amount of the asset to withdraw.\n     */\n    function _withdrawFromYSD(address asset, uint256 amount) internal virtual {\n        // Withdraw gauge from YSD which transfers to msg.sender\n        IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).withdraw(asset, amount);\n    }\n\n    /**\n     * @notice Return the amount of the asset deposited by this contract in the YearnStakingDelegate.\n     * @param asset The address of the asset to check.\n     * @return The amount of the asset deposited in the YearnStakingDelegate.\n     */\n    function depositedInYSD(address asset) public view returns (uint256) {\n        return IYearnStakingDelegate(_YEARN_STAKING_DELEGATE).balanceOf(address(this), asset);\n    }\n}\n"
      },
      "src/interfaces/IYearnStakingDelegate.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.18;\n\nimport { IVotingYFI } from \"./deps/yearn/veYFI/IVotingYFI.sol\";\n\ninterface IYearnStakingDelegate {\n    // Struct definitions\n    struct RewardSplit {\n        uint64 treasury;\n        uint64 coveYfi;\n        uint64 user;\n        uint64 lock;\n    }\n\n    struct ExitRewardSplit {\n        uint128 treasury;\n        uint128 coveYfi;\n    }\n\n    struct BoostRewardSplit {\n        uint128 treasury;\n        uint128 coveYfi;\n    }\n\n    function deposit(address gauge, uint256 amount) external;\n    function withdraw(address gauge, uint256 amount) external;\n    function withdraw(address gauge, uint256 amount, address receiver) external;\n    function lockYfi(uint256 amount) external returns (IVotingYFI.LockedBalance memory);\n    function harvest(address vault) external returns (uint256);\n    function setCoveYfiRewardForwarder(address forwarder) external;\n    function setGaugeRewardSplit(\n        address gauge,\n        uint64 treasuryPct,\n        uint64 coveYfiPct,\n        uint64 userPct,\n        uint64 veYfiPct\n    )\n        external;\n\n    function setBoostRewardSplit(uint128 treasuryPct, uint128 coveYfiPct) external;\n    function setExitRewardSplit(uint128 treasuryPct, uint128 coveYfiPct) external;\n    function setSwapAndLock(address swapAndLock) external;\n    function balanceOf(address user, address gauge) external view returns (uint256);\n    function totalDeposited(address gauge) external view returns (uint256);\n    function depositLimit(address gauge) external view returns (uint256);\n    function availableDepositLimit(address gauge) external view returns (uint256);\n    function gaugeStakingRewards(address gauge) external view returns (address);\n    function gaugeRewardReceivers(address gauge) external view returns (address);\n    function getGaugeRewardSplit(address gauge) external view returns (RewardSplit memory);\n    function getBoostRewardSplit() external view returns (BoostRewardSplit memory);\n    function getExitRewardSplit() external view returns (ExitRewardSplit memory);\n    function treasury() external view returns (address);\n}\n"
      },
      "src/libraries/Errors.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.8.18;\n\n/// @title Errors\n/// @notice Library containing all custom errors the protocol may revert with.\nlibrary Errors {\n    //// MASTER REGISTRY ////\n\n    /// @notice Thrown when the registry name given is empty.\n    error NameEmpty();\n\n    /// @notice Thrown when the registry address given is empty.\n    error AddressEmpty();\n\n    /// @notice Thrown when the registry name is found when calling addRegistry().\n    error RegistryNameFound(bytes32 name);\n\n    /// @notice Thrown when the registry name is not found but is expected to be.\n    error RegistryNameNotFound(bytes32 name);\n\n    /// @notice Thrown when the registry address is not found but is expected to be.\n    error RegistryAddressNotFound(address registryAddress);\n\n    /// @notice Thrown when the registry name and version is not found but is expected to be.\n    error RegistryNameVersionNotFound(bytes32 name, uint256 version);\n\n    /// @notice Thrown when a duplicate registry address is found.\n    error DuplicateRegistryAddress(address registryAddress);\n\n    //// YEARN STAKING DELEGATE ////\n\n    /// @notice Error for when an address is zero which is not allowed.\n    error ZeroAddress();\n\n    /// @notice Error for when an amount is zero which is not allowed.\n    error ZeroAmount();\n\n    /// @notice Error for when a reward split is invalid.\n    error InvalidRewardSplit();\n\n    /// @notice Error for when the treasury percentage is too high.\n    error TreasuryPctTooHigh();\n\n    /// @notice Error for when perpetual lock is enabled and an action cannot be taken.\n    error PerpetualLockEnabled();\n\n    /// @notice Error for when perpetual lock is disabled and an action cannot be taken.\n    error PerpetualLockDisabled();\n\n    /// @notice Error for when swap and lock settings are not set.\n    error SwapAndLockNotSet();\n\n    /// @notice Error for when gauge rewards have already been added.\n    error GaugeRewardsAlreadyAdded();\n\n    /// @notice Error for when gauge rewards have not yet been added.\n    error GaugeRewardsNotYetAdded();\n\n    /// @notice Error for when execution of an action is not allowed.\n    error ExecutionNotAllowed();\n\n    /// @notice Error for when execution of an action has failed.\n    error ExecutionFailed();\n\n    /// @notice Error for when Cove YFI reward forwarder is not set.\n    error CoveYfiRewardForwarderNotSet();\n\n    //// STAKING DELEGATE REWARDS ////\n\n    /// @notice Error for when a rescue operation is not allowed.\n    error RescueNotAllowed();\n\n    /// @notice Error for when the previous rewards period has not been completed.\n    error PreviousRewardsPeriodNotCompleted();\n\n    /// @notice Error for when only the staking delegate can update a user's balance.\n    error OnlyStakingDelegateCanUpdateUserBalance();\n\n    /// @notice Error for when only the staking delegate can add a staking token.\n    error OnlyStakingDelegateCanAddStakingToken();\n\n    /// @notice Error for when only the reward distributor can notify the reward amount.\n    error OnlyRewardDistributorCanNotifyRewardAmount();\n\n    /// @notice Error for when a staking token has already been added.\n    error StakingTokenAlreadyAdded();\n\n    /// @notice Error for when a staking token has not been added.\n    error StakingTokenNotAdded();\n\n    /// @notice Error for when the reward rate is too low.\n    error RewardRateTooLow();\n\n    /// @notice Error for when the reward duration cannot be zero.\n    error RewardDurationCannotBeZero();\n\n    //// WRAPPED STRATEGY CURVE SWAPPER ////\n\n    /// @notice Error for when slippage is too high.\n    error SlippageTooHigh();\n\n    /// @notice Error for when invalid tokens are received.\n    error InvalidTokensReceived();\n\n    /// CURVE ROUTER SWAPPER ///\n\n    /*\n     * @notice Error for when the from token is invalid.\n     * @param intendedFromToken The intended from token address.\n     * @param actualFromToken The actual from token address received.\n     */\n    error InvalidFromToken(address intendedFromToken, address actualFromToken);\n\n    /*\n     * @notice Error for when the to token is invalid.\n     * @param intendedToToken The intended to token address.\n     * @param actualToToken The actual to token address received.\n     */\n    error InvalidToToken(address intendedToToken, address actualToToken);\n\n    /// @notice Error for when the expected amount is zero.\n    error ExpectedAmountZero();\n\n    /// @notice Error for when swap parameters are invalid.\n    error InvalidSwapParams();\n\n    /// SWAP AND LOCK ///\n\n    /// @notice Error for when the same address is used in a context where it is not allowed.\n    error SameAddress();\n\n    //// COVEYFI ////\n\n    /// @notice Error for when only minting is enabled.\n    error OnlyMintingEnabled();\n\n    /// RESCUABLE ///\n\n    /// @notice Error for when an ETH transfer of zero is attempted.\n    error ZeroEthTransfer();\n\n    /// @notice Error for when an ETH transfer fails.\n    error EthTransferFailed();\n\n    /// @notice Error for when a token transfer of zero is attempted.\n    error ZeroTokenTransfer();\n\n    /// GAUGE REWARD RECEIVER ///\n\n    /// @notice Error for when an action is not authorized.\n    error NotAuthorized();\n\n    /// @notice Error for when rescuing a reward token is not allowed.\n    error CannotRescueRewardToken();\n\n    /// DYFI REDEEMER ///\n\n    /// @notice Error for when an array length is invalid.\n    error InvalidArrayLength();\n\n    /// @notice Error for when a price feed is outdated.\n    error PriceFeedOutdated();\n\n    /// @notice Error for when a price feed round is incorrect.\n    error PriceFeedIncorrectRound();\n\n    /// @notice Error for when a price feed returns a zero price.\n    error PriceFeedReturnedZeroPrice();\n\n    /// @notice Error for when there is no DYFI to redeem.\n    error NoDYfiToRedeem();\n\n    /// @notice Error for when an ETH transfer for caller reward fails.\n    error CallerRewardEthTransferFailed();\n\n    /// COVE YEARN GAUGE FACTORY ///\n\n    /// @notice Error for when a gauge has already been deployed.\n    error GaugeAlreadyDeployed();\n\n    /// @notice Error for when a gauge has not been deployed.\n    error GaugeNotDeployed();\n\n    /// MINICHEF V3 ////\n\n    /// @notice Error for when an LP token is invalid.\n    error InvalidLPToken();\n\n    /// @notice Error for when an LP token has not been added.\n    error LPTokenNotAdded();\n\n    /// @notice Error for when an LP token does not match the pool ID.\n    error LPTokenDoesNotMatchPoolId();\n\n    /// @notice Error for when there is an insufficient balance.\n    error InsufficientBalance();\n\n    /// @notice Error for when an LP token has already been added.\n    error LPTokenAlreadyAdded();\n\n    /// @notice Error for when the reward rate is too high.\n    error RewardRateTooHigh();\n\n    /// Yearn4626RouterExt ///\n\n    /// @notice Error for when there are insufficient shares.\n    error InsufficientShares();\n\n    /// @notice Error for when the 'to' address is invalid.\n    error InvalidTo();\n\n    /// @notice Error esure the has enough remaining gas.\n    error InsufficientGas();\n\n    /// TESTING ///\n\n    /// @notice Error for when there is not enough balance to take away.\n    error TakeAwayNotEnoughBalance();\n\n    /// @notice Error for when a strategy has not been added to a vault.\n    error StrategyNotAddedToVault();\n\n    /// COVE TOKEN ///\n\n    /// @notice Error for when a transfer is attempted before it is allowed.\n    error TransferNotAllowedYet();\n\n    /// @notice Error for when an address is being added as both a sender and a receiver.\n    error CannotBeBothSenderAndReceiver();\n\n    /// @notice Error for when an unpause is attempted too early.\n    error UnpauseTooEarly();\n\n    /// @notice Error for when the pause period is too long.\n    error PausePeriodTooLong();\n\n    /// @notice Error for when minting is attempted too early.\n    error MintingAllowedTooEarly();\n\n    /// @notice Error for when the mint amount exceeds the cap.\n    error InflationTooLarge();\n\n    /*\n     * @notice Error for when an unauthorized account attempts an action requiring a specific role.\n     * @param account The account attempting the unauthorized action.\n     * @param neededRole The role required for the action.\n     */\n    error AccessControlEnumerableUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /// @notice Error for when an action is unauthorized.\n    error Unauthorized();\n\n    /// @notice Error for when a pause is expected but not enacted.\n    error ExpectedPause();\n\n    /// COVE YEARN GAUGE FACTORY ///\n\n    /// @notice Error for when an address is not a contract.\n    error AddressNotContract();\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "lib/tokenized-strategy/src/interfaces/ITokenizedStrategy.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity 0.8.18;\n\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC4626} from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport {IERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\n\n// Interface that implements the 4626 standard and the implementation functions\ninterface ITokenizedStrategy is IERC4626, IERC20Permit {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event StrategyShutdown();\n\n    event NewTokenizedStrategy(\n        address indexed strategy,\n        address indexed asset,\n        string apiVersion\n    );\n\n    event Reported(\n        uint256 profit,\n        uint256 loss,\n        uint256 protocolFees,\n        uint256 performanceFees\n    );\n\n    event UpdatePerformanceFeeRecipient(\n        address indexed newPerformanceFeeRecipient\n    );\n\n    event UpdateKeeper(address indexed newKeeper);\n\n    event UpdatePerformanceFee(uint16 newPerformanceFee);\n\n    event UpdateManagement(address indexed newManagement);\n\n    event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);\n\n    event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);\n\n    event UpdatePendingManagement(address indexed newPendingManagement);\n\n    /*//////////////////////////////////////////////////////////////\n                           INITIALIZATION\n    //////////////////////////////////////////////////////////////*/\n\n    function initialize(\n        address _asset,\n        string memory _name,\n        address _management,\n        address _performanceFeeRecipient,\n        address _keeper\n    ) external;\n\n    /*//////////////////////////////////////////////////////////////\n                    NON-STANDARD 4626 OPTIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner,\n        uint256 maxLoss\n    ) external returns (uint256);\n\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner,\n        uint256 maxLoss\n    ) external returns (uint256);\n\n    /*//////////////////////////////////////////////////////////////\n                        MODIFIER HELPERS\n    //////////////////////////////////////////////////////////////*/\n\n    function requireManagement(address _sender) external view;\n\n    function requireKeeperOrManagement(address _sender) external view;\n\n    function requireEmergencyAuthorized(address _sender) external view;\n\n    /*//////////////////////////////////////////////////////////////\n                        KEEPERS FUNCTIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function tend() external;\n\n    function report() external returns (uint256 _profit, uint256 _loss);\n\n    /*//////////////////////////////////////////////////////////////\n                        CONSTANTS\n    //////////////////////////////////////////////////////////////*/\n\n    function MAX_FEE() external view returns (uint16);\n\n    function FACTORY() external view returns (address);\n\n    /*//////////////////////////////////////////////////////////////\n                            GETTERS\n    //////////////////////////////////////////////////////////////*/\n\n    function apiVersion() external view returns (string memory);\n\n    function pricePerShare() external view returns (uint256);\n\n    function management() external view returns (address);\n\n    function pendingManagement() external view returns (address);\n\n    function keeper() external view returns (address);\n\n    function emergencyAdmin() external view returns (address);\n\n    function performanceFee() external view returns (uint16);\n\n    function performanceFeeRecipient() external view returns (address);\n\n    function fullProfitUnlockDate() external view returns (uint256);\n\n    function profitUnlockingRate() external view returns (uint256);\n\n    function profitMaxUnlockTime() external view returns (uint256);\n\n    function lastReport() external view returns (uint256);\n\n    function isShutdown() external view returns (bool);\n\n    function unlockedShares() external view returns (uint256);\n\n    /*//////////////////////////////////////////////////////////////\n                            SETTERS\n    //////////////////////////////////////////////////////////////*/\n\n    function setPendingManagement(address) external;\n\n    function acceptManagement() external;\n\n    function setKeeper(address _keeper) external;\n\n    function setEmergencyAdmin(address _emergencyAdmin) external;\n\n    function setPerformanceFee(uint16 _performanceFee) external;\n\n    function setPerformanceFeeRecipient(\n        address _performanceFeeRecipient\n    ) external;\n\n    function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external;\n\n    function shutdownStrategy() external;\n\n    function emergencyWithdraw(uint256 _amount) external;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/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"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (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 *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\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     * CAUTION: See Security Considerations above.\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"
      },
      "lib/openzeppelin-contracts/contracts/utils/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"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/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"
      },
      "src/interfaces/deps/curve/ICurveRouter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface ICurveRouter {\n    /**\n     * @notice Performs an exchange operation.\n     * @dev `route` and `swapParams` should be determined off chain.\n     * @param route An array of [initial token, pool or zap, token, pool or zap, token, ...]. The iteration continues\n     * until a pool address of 0x00, then the last given token is transferred to `_receiver`\n     * @param swapParams A multidimensional array of [i, j, swap type, pool_type, n_coins] where:\n     * i is the index of the input token,\n     * j is the index of the output token,\n     * swap type should be:\n     *         - 1 for `exchange`,\n     *         - 2 for `exchange_underlying`,\n     *         - 3 for underlying exchange via zap: factory stable metapools with lending base pool\n     * `exchange_underlying` and factory crypto-metapools underlying exchange (`exchange` method in zap);\n     *         - 4 for coin -> LP token \"exchange\" (actually `add_liquidity`),\n     *         - 5 for lending pool underlying coin -> LP token \"exchange\" (actually `add_liquidity`),\n     *         - 6 for LP token -> coin \"exchange\" (actually `remove_liquidity_one_coin`),\n     *         - 7 for LP token -> lending or fake pool underlying coin \"exchange\" (actually\n     * `remove_liquidity_one_coin`),\n     *         - 8 for ETH <-> WETH, ETH -> stETH or ETH -> frxETH, stETH <-> wstETH, frxETH <-> sfrxETH, ETH -> wBETH,\n     *         - 9 for SNX swaps (sUSD, sEUR, sETH, sBTC)\n     *         Pool type:\n     *         - 1 - stable, 2 - crypto, 3 - tricrypto, 4 - llama\n     *         `n_coins` indicates the number of coins in the pool\n     * @param amount The amount of `route[0]` to be sent.\n     * @param expected The minimum amount received after the final swap.\n     * @return The received amount of the final output token.\n     */\n    function exchange(\n        address[11] calldata route,\n        uint256[5][5] calldata swapParams,\n        uint256 amount,\n        uint256 expected\n    )\n        external\n        payable\n        returns (uint256);\n\n    /**\n     * @notice Performs up to 5 swaps in a single transaction.\n     * @dev Routing and swap params must be determined off-chain. This functionality is designed for gas efficiency over\n     * ease-of-use.\n     * @param route Array of the route.\n     * @param swapParams Parameters for the swap operation.\n     * @param amount The amount of `route[0]` to be sent.\n     * @param expected The minimum amount expected after all the swaps.\n     * @param pools Array of pool addresses for swaps via zap contracts. Needed only for swap type = 3.\n     * @param receiver The address to transfer the final output token to.\n     * @return The received amount of the final output token.\n     */\n    function exchange(\n        address[11] calldata route,\n        uint256[5][5] calldata swapParams,\n        uint256 amount,\n        uint256 expected,\n        address[5] calldata pools,\n        address receiver\n    )\n        external\n        payable\n        returns (uint256);\n\n    /**\n     * @notice Executes an exchange operation.\n     * @param route Array containing the route for exchange.\n     * @param swapParams Parameters for the swap operation.\n     * @param amount The amount of input token to be sent.\n     * @param expected The minimum amount expected after the exchange.\n     * @param pools Array of pool addresses for swaps via zap contracts.\n     * @return The received amount of the final output token.\n     */\n    function exchange(\n        address[11] calldata route,\n        uint256[5][5] calldata swapParams,\n        uint256 amount,\n        uint256 expected,\n        address[5] calldata pools\n    )\n        external\n        payable\n        returns (uint256);\n\n    function get_dy(\n        address[11] calldata route,\n        uint256[5][5] calldata swapParams,\n        uint256 amount,\n        address[5] calldata pools\n    )\n        external\n        view\n        returns (uint256);\n}\n"
      },
      "src/interfaces/deps/yearn/veYFI/IYearnVaultV2.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\n// @dev YearnVaultV2 does not follow ERC4626 interface for `asset()` instead it uses `token()`\ninterface IYearnVaultV2 {\n    function token() external view returns (address);\n    function deposit(uint256 amount, address recipient) external returns (uint256 shares);\n    function deposit(uint256 amount) external returns (uint256 shares);\n    function withdraw(uint256 shares, address recipient) external returns (uint256 amount);\n    function pricePerShare() external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function totalAssets() external view returns (uint256);\n    function lastReport() external view returns (uint256);\n    function lockedProfitDegradation() external view returns (uint256);\n    function lockedProfit() external view returns (uint256);\n}\n"
      },
      "src/interfaces/deps/yearn/veYFI/IVotingYFI.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IVotingYFI is IERC20 {\n    event ModifyLock(address indexed sender, address indexed user, uint256 amount, uint256 locktime, uint256 ts);\n    event Withdraw(address indexed user, uint256 amount, uint256 ts);\n    event Penalty(address indexed user, uint256 amount, uint256 ts);\n    event Supply(uint256 oldSupply, uint256 newSupply, uint256 ts);\n\n    struct LockedBalance {\n        uint256 amount;\n        uint256 end;\n    }\n\n    struct Withdrawn {\n        uint256 amount;\n        uint256 penalty;\n    }\n\n    struct Point {\n        int128 bias;\n        int128 slope;\n        uint256 ts;\n        uint256 blk;\n    }\n\n    function totalSupply() external view returns (uint256);\n\n    function locked(address _user) external view returns (LockedBalance memory);\n\n    function modify_lock(\n        uint256 _amount,\n        uint256 _unlock_time,\n        address _user\n    )\n        external\n        returns (LockedBalance memory);\n\n    function withdraw() external returns (Withdrawn memory);\n\n    function point_history(address user, uint256 epoch) external view returns (Point memory);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "tokenized-strategy/=lib/tokenized-strategy/src/",
        "yearn-vaults-v3/=lib/yearn-vaults-v3/contracts/",
        "Yearn-ERC4626-Router/=lib/Yearn-ERC4626-Router/src/",
        "solmate/=lib/permit2/lib/solmate/src/",
        "permit2/=lib/permit2/src/",
        "forge-std/=lib/forge-std/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "@crytic/properties/=lib/properties/",
        "forge-deploy/=lib/forge-deploy/contracts/",
        "script/=script/",
        "src/=src/",
        "test/=test/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}