creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/base/Roles/AccountantWithRateProviders.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport {FixedPointMathLib} from \"@solmate/utils/FixedPointMathLib.sol\";\nimport {IRateProvider} from \"src/interfaces/IRateProvider.sol\";\nimport {ERC20} from \"@solmate/tokens/ERC20.sol\";\nimport {SafeTransferLib} from \"@solmate/utils/SafeTransferLib.sol\";\nimport {BoringVault} from \"src/base/BoringVault.sol\";\nimport {Auth, Authority} from \"@solmate/auth/Auth.sol\";\n\ncontract AccountantWithRateProviders is Auth, IRateProvider {\n    using FixedPointMathLib for uint256;\n    using SafeTransferLib for ERC20;\n\n    // ========================================= STRUCTS =========================================\n\n    /**\n     * @param payoutAddress the address `claimFees` sends fees to\n     * @param feesOwedInBase total pending fees owed in terms of base\n     * @param totalSharesLastUpdate total amount of shares the last exchange rate update\n     * @param exchangeRate the current exchange rate in terms of base\n     * @param allowedExchangeRateChangeUpper the max allowed change to exchange rate from an update\n     * @param allowedExchangeRateChangeLower the min allowed change to exchange rate from an update\n     * @param lastUpdateTimestamp the block timestamp of the last exchange rate update\n     * @param isPaused whether or not this contract is paused\n     * @param minimumUpdateDelayInSeconds the minimum amount of time that must pass between\n     *        exchange rate updates, such that the update won't trigger the contract to be paused\n     * @param managementFee the management fee\n     */\n    struct AccountantState {\n        address payoutAddress;\n        uint128 feesOwedInBase;\n        uint128 totalSharesLastUpdate;\n        uint96 exchangeRate;\n        uint16 allowedExchangeRateChangeUpper;\n        uint16 allowedExchangeRateChangeLower;\n        uint64 lastUpdateTimestamp;\n        bool isPaused;\n        uint32 minimumUpdateDelayInSeconds;\n        uint16 managementFee;\n    }\n\n    /**\n     * @param isPeggedToBase whether or not the asset is 1:1 with the base asset\n     * @param rateProvider the rate provider for this asset if `isPeggedToBase` is false\n     */\n    struct RateProviderData {\n        bool isPeggedToBase;\n        IRateProvider rateProvider;\n    }\n\n    // ========================================= STATE =========================================\n\n    /**\n     * @notice Store the accountant state in 3 packed slots.\n     */\n    AccountantState public accountantState;\n\n    /**\n     * @notice Maps ERC20s to their RateProviderData.\n     */\n    mapping(ERC20 => RateProviderData) public rateProviderData;\n\n    //============================== ERRORS ===============================\n\n    error AccountantWithRateProviders__UpperBoundTooSmall();\n    error AccountantWithRateProviders__LowerBoundTooLarge();\n    error AccountantWithRateProviders__ManagementFeeTooLarge();\n    error AccountantWithRateProviders__Paused();\n    error AccountantWithRateProviders__ZeroFeesOwed();\n    error AccountantWithRateProviders__OnlyCallableByBoringVault();\n    error AccountantWithRateProviders__UpdateDelayTooLarge();\n\n    //============================== EVENTS ===============================\n\n    event Paused();\n    event Unpaused();\n    event DelayInSecondsUpdated(uint32 oldDelay, uint32 newDelay);\n    event UpperBoundUpdated(uint16 oldBound, uint16 newBound);\n    event LowerBoundUpdated(uint16 oldBound, uint16 newBound);\n    event ManagementFeeUpdated(uint16 oldFee, uint16 newFee);\n    event PayoutAddressUpdated(address oldPayout, address newPayout);\n    event RateProviderUpdated(address asset, bool isPegged, address rateProvider);\n    event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime);\n    event FeesClaimed(address indexed feeAsset, uint256 amount);\n\n    //============================== IMMUTABLES ===============================\n\n    /**\n     * @notice The base asset rates are provided in.\n     */\n    ERC20 public immutable base;\n\n    /**\n     * @notice The decimals rates are provided in.\n     */\n    uint8 public immutable decimals;\n\n    /**\n     * @notice The BoringVault this accountant is working with.\n     *         Used to determine share supply for fee calculation.\n     */\n    BoringVault public immutable vault;\n\n    /**\n     * @notice One share of the BoringVault.\n     */\n    uint256 internal immutable ONE_SHARE;\n\n    constructor(\n        address _owner,\n        address _vault,\n        address payoutAddress,\n        uint96 startingExchangeRate,\n        address _base,\n        uint16 allowedExchangeRateChangeUpper,\n        uint16 allowedExchangeRateChangeLower,\n        uint32 minimumUpdateDelayInSeconds,\n        uint16 managementFee\n    ) Auth(_owner, Authority(address(0))) {\n        base = ERC20(_base);\n        decimals = ERC20(_base).decimals();\n        vault = BoringVault(payable(_vault));\n        ONE_SHARE = 10 ** vault.decimals();\n        accountantState = AccountantState({\n            payoutAddress: payoutAddress,\n            feesOwedInBase: 0,\n            totalSharesLastUpdate: uint128(vault.totalSupply()),\n            exchangeRate: startingExchangeRate,\n            allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper,\n            allowedExchangeRateChangeLower: allowedExchangeRateChangeLower,\n            lastUpdateTimestamp: uint64(block.timestamp),\n            isPaused: false,\n            minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds,\n            managementFee: managementFee\n        });\n    }\n\n    // ========================================= ADMIN FUNCTIONS =========================================\n    /**\n     * @notice Pause this contract, which prevents future calls to `updateExchangeRate`, and any safe rate\n     *         calls will revert.\n     * @dev Callable by MULTISIG_ROLE.\n     */\n    function pause() external requiresAuth {\n        accountantState.isPaused = true;\n        emit Paused();\n    }\n\n    /**\n     * @notice Unpause this contract, which allows future calls to `updateExchangeRate`, and any safe rate\n     *         calls will stop reverting.\n     * @dev Callable by MULTISIG_ROLE.\n     */\n    function unpause() external requiresAuth {\n        accountantState.isPaused = false;\n        emit Unpaused();\n    }\n\n    /**\n     * @notice Update the minimum time delay between `updateExchangeRate` calls.\n     * @dev There are no input requirements, as it is possible the admin would want\n     *      the exchange rate updated as frequently as needed.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function updateDelay(uint32 minimumUpdateDelayInSeconds) external requiresAuth {\n        if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge();\n        uint32 oldDelay = accountantState.minimumUpdateDelayInSeconds;\n        accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds;\n        emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds);\n    }\n\n    /**\n     * @notice Update the allowed upper bound change of exchange rate between `updateExchangeRateCalls`.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth {\n        if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall();\n        uint16 oldBound = accountantState.allowedExchangeRateChangeUpper;\n        accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper;\n        emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper);\n    }\n\n    /**\n     * @notice Update the allowed lower bound change of exchange rate between `updateExchangeRateCalls`.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth {\n        if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge();\n        uint16 oldBound = accountantState.allowedExchangeRateChangeLower;\n        accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower;\n        emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower);\n    }\n\n    /**\n     * @notice Update the management fee to a new value.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function updateManagementFee(uint16 managementFee) external requiresAuth {\n        if (managementFee > 0.2e4) revert AccountantWithRateProviders__ManagementFeeTooLarge();\n        uint16 oldFee = accountantState.managementFee;\n        accountantState.managementFee = managementFee;\n        emit ManagementFeeUpdated(oldFee, managementFee);\n    }\n\n    /**\n     * @notice Update the payout address fees are sent to.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function updatePayoutAddress(address payoutAddress) external requiresAuth {\n        address oldPayout = accountantState.payoutAddress;\n        accountantState.payoutAddress = payoutAddress;\n        emit PayoutAddressUpdated(oldPayout, payoutAddress);\n    }\n\n    /**\n     * @notice Update the rate provider data for a specific `asset`.\n     * @dev Rate providers must return rates in terms of `base` or\n     * an asset pegged to base and they must use the same decimals\n     * as `asset`.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth {\n        rateProviderData[asset] =\n            RateProviderData({isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider)});\n        emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider);\n    }\n\n    // ========================================= UPDATE EXCHANGE RATE/FEES FUNCTIONS =========================================\n\n    /**\n     * @notice Updates this contract exchangeRate.\n     * @dev If new exchange rate is outside of accepted bounds, or if not enough time has passed, this\n     *      will pause the contract, and this function will NOT calculate fees owed.\n     * @dev Callable by UPDATE_EXCHANGE_RATE_ROLE.\n     */\n    function updateExchangeRate(uint96 newExchangeRate) external requiresAuth {\n        AccountantState storage state = accountantState;\n        if (state.isPaused) revert AccountantWithRateProviders__Paused();\n        uint64 currentTime = uint64(block.timestamp);\n        uint256 currentExchangeRate = state.exchangeRate;\n        uint256 currentTotalShares = vault.totalSupply();\n        if (\n            currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds\n                || newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4)\n                || newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4)\n        ) {\n            // Instead of reverting, pause the contract. This way the exchange rate updater is able to update the exchange rate\n            // to a better value, and pause it.\n            state.isPaused = true;\n        } else {\n            // Only update fees if we are not paused.\n            // Update fee accounting.\n            uint256 shareSupplyToUse = currentTotalShares;\n            // Use the minimum between current total supply and total supply for last update.\n            if (state.totalSharesLastUpdate < shareSupplyToUse) {\n                shareSupplyToUse = state.totalSharesLastUpdate;\n            }\n\n            // Determine management fees owned.\n            uint256 timeDelta = currentTime - state.lastUpdateTimestamp;\n            uint256 minimumAssets = newExchangeRate > currentExchangeRate\n                ? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE)\n                : shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE);\n            uint256 managementFeesAnnual = minimumAssets.mulDivDown(state.managementFee, 1e4);\n            uint256 newFeesOwedInBase = managementFeesAnnual.mulDivDown(timeDelta, 365 days);\n\n            state.feesOwedInBase += uint128(newFeesOwedInBase);\n        }\n\n        state.exchangeRate = newExchangeRate;\n        state.totalSharesLastUpdate = uint128(currentTotalShares);\n        state.lastUpdateTimestamp = currentTime;\n\n        emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime);\n    }\n\n    /**\n     * @notice Claim pending fees.\n     * @dev This function must be called by the BoringVault.\n     * @dev This function will lose precision if the exchange rate\n     *      decimals is greater than the feeAsset's decimals.\n     */\n    function claimFees(ERC20 feeAsset) external {\n        if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault();\n\n        AccountantState storage state = accountantState;\n        if (state.isPaused) revert AccountantWithRateProviders__Paused();\n        if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed();\n\n        // Determine amount of fees owed in feeAsset.\n        uint256 feesOwedInFeeAsset;\n        RateProviderData memory data = rateProviderData[feeAsset];\n        if (address(feeAsset) == address(base)) {\n            feesOwedInFeeAsset = state.feesOwedInBase;\n        } else {\n            uint8 feeAssetDecimals = ERC20(feeAsset).decimals();\n            uint256 feesOwedInBaseUsingFeeAssetDecimals =\n                changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals);\n            if (data.isPeggedToBase) {\n                feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals;\n            } else {\n                uint256 rate = data.rateProvider.getRate();\n                feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate);\n            }\n        }\n        // Zero out fees owed.\n        state.feesOwedInBase = 0;\n        // Transfer fee asset to payout address.\n        feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset);\n\n        emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset);\n    }\n\n    // ========================================= RATE FUNCTIONS =========================================\n\n    /**\n     * @notice Get this BoringVault's current rate in the base.\n     */\n    function getRate() public view returns (uint256 rate) {\n        rate = accountantState.exchangeRate;\n    }\n\n    /**\n     * @notice Get this BoringVault's current rate in the base.\n     * @dev Revert if paused.\n     */\n    function getRateSafe() external view returns (uint256 rate) {\n        if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();\n        rate = getRate();\n    }\n\n    /**\n     * @notice Get this BoringVault's current rate in the provided quote.\n     * @dev `quote` must have its RateProviderData set, else this will revert.\n     * @dev This function will lose precision if the exchange rate\n     *      decimals is greater than the quote's decimals.\n     */\n    function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) {\n        if (address(quote) == address(base)) {\n            rateInQuote = accountantState.exchangeRate;\n        } else {\n            RateProviderData memory data = rateProviderData[quote];\n            uint8 quoteDecimals = ERC20(quote).decimals();\n            uint256 exchangeRateInQuoteDecimals = changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals);\n            if (data.isPeggedToBase) {\n                rateInQuote = exchangeRateInQuoteDecimals;\n            } else {\n                uint256 quoteRate = data.rateProvider.getRate();\n                uint256 oneQuote = 10 ** quoteDecimals;\n                rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate);\n            }\n        }\n    }\n\n    /**\n     * @notice Get this BoringVault's current rate in the provided quote.\n     * @dev `quote` must have its RateProviderData set, else this will revert.\n     * @dev Revert if paused.\n     */\n    function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) {\n        if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();\n        rateInQuote = getRateInQuote(quote);\n    }\n\n    // ========================================= INTERNAL HELPER FUNCTIONS =========================================\n    /**\n     * @notice Used to change the decimals of precision used for an amount.\n     */\n    function changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {\n        if (fromDecimals == toDecimals) {\n            return amount;\n        } else if (fromDecimals < toDecimals) {\n            return amount * 10 ** (toDecimals - fromDecimals);\n        } else {\n            return amount / 10 ** (fromDecimals - toDecimals);\n        }\n    }\n}\n"
      },
      "lib/solmate/src/utils/FixedPointMathLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\nlibrary FixedPointMathLib {\n    /*//////////////////////////////////////////////////////////////\n                    SIMPLIFIED FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant MAX_UINT256 = 2**256 - 1;\n\n    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n    }\n\n    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\n    }\n\n    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\n    }\n\n    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                    LOW LEVEL FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function mulDivDown(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // Divide x * y by the denominator.\n            z := div(mul(x, y), denominator)\n        }\n    }\n\n    function mulDivUp(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // If x * y modulo the denominator is strictly greater than 0,\n            // 1 is added to round up the division of x * y by the denominator.\n            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\n        }\n    }\n\n    function rpow(\n        uint256 x,\n        uint256 n,\n        uint256 scalar\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            switch x\n            case 0 {\n                switch n\n                case 0 {\n                    // 0 ** 0 = 1\n                    z := scalar\n                }\n                default {\n                    // 0 ** n = 0\n                    z := 0\n                }\n            }\n            default {\n                switch mod(n, 2)\n                case 0 {\n                    // If n is even, store scalar in z for now.\n                    z := scalar\n                }\n                default {\n                    // If n is odd, store x in z for now.\n                    z := x\n                }\n\n                // Shifting right by 1 is like dividing by 2.\n                let half := shr(1, scalar)\n\n                for {\n                    // Shift n right by 1 before looping to halve it.\n                    n := shr(1, n)\n                } n {\n                    // Shift n right by 1 each iteration to halve it.\n                    n := shr(1, n)\n                } {\n                    // Revert immediately if x ** 2 would overflow.\n                    // Equivalent to iszero(eq(div(xx, x), x)) here.\n                    if shr(128, x) {\n                        revert(0, 0)\n                    }\n\n                    // Store x squared.\n                    let xx := mul(x, x)\n\n                    // Round to the nearest number.\n                    let xxRound := add(xx, half)\n\n                    // Revert if xx + half overflowed.\n                    if lt(xxRound, xx) {\n                        revert(0, 0)\n                    }\n\n                    // Set x to scaled xxRound.\n                    x := div(xxRound, scalar)\n\n                    // If n is even:\n                    if mod(n, 2) {\n                        // Compute z * x.\n                        let zx := mul(z, x)\n\n                        // If z * x overflowed:\n                        if iszero(eq(div(zx, x), z)) {\n                            // Revert if x is non-zero.\n                            if iszero(iszero(x)) {\n                                revert(0, 0)\n                            }\n                        }\n\n                        // Round to the nearest number.\n                        let zxRound := add(zx, half)\n\n                        // Revert if zx + half overflowed.\n                        if lt(zxRound, zx) {\n                            revert(0, 0)\n                        }\n\n                        // Return properly scaled zxRound.\n                        z := div(zxRound, scalar)\n                    }\n                }\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        GENERAL NUMBER UTILITIES\n    //////////////////////////////////////////////////////////////*/\n\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let y := x // We start y at x, which will help us make our initial estimate.\n\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // We check y >= 2^(k + 8) but shift right by k bits\n            // each branch to ensure that if x >= 256, then y >= 256.\n            if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n                y := shr(128, y)\n                z := shl(64, z)\n            }\n            if iszero(lt(y, 0x1000000000000000000)) {\n                y := shr(64, y)\n                z := shl(32, z)\n            }\n            if iszero(lt(y, 0x10000000000)) {\n                y := shr(32, y)\n                z := shl(16, z)\n            }\n            if iszero(lt(y, 0x1000000)) {\n                y := shr(16, y)\n                z := shl(8, z)\n            }\n\n            // Goal was to get z*z*y within a small factor of x. More iterations could\n            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n            // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n            // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n            // There is no overflow risk here since y < 2^136 after the first branch above.\n            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If x+1 is a perfect square, the Babylonian method cycles between\n            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Mod x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            z := mod(x, y)\n        }\n    }\n\n    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Divide x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            r := div(x, y)\n        }\n    }\n\n    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Add 1 to x * y if x % y > 0. Note this will\n            // return 0 instead of reverting if y is zero.\n            z := add(gt(mod(x, y), 0), div(x, y))\n        }\n    }\n}\n"
      },
      "src/interfaces/IRateProvider.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\npragma solidity ^0.8.0;\n\ninterface IRateProvider {\n    function getRate() external view returns (uint256);\n}\n"
      },
      "lib/solmate/src/tokens/ERC20.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /*//////////////////////////////////////////////////////////////\n                            METADATA STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    string public name;\n\n    string public symbol;\n\n    uint8 public immutable decimals;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC20 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 public totalSupply;\n\n    mapping(address => uint256) public balanceOf;\n\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /*//////////////////////////////////////////////////////////////\n                            EIP-2612 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal immutable INITIAL_CHAIN_ID;\n\n    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n    mapping(address => uint256) public nonces;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) {\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n\n        INITIAL_CHAIN_ID = block.chainid;\n        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               ERC20 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        balanceOf[msg.sender] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual returns (bool) {\n        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n        balanceOf[from] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        return true;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             EIP-2612 LOGIC\n    //////////////////////////////////////////////////////////////*/\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    ) public virtual {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n        // Unchecked because the only math done is incrementing\n        // the owner's nonce which cannot realistically overflow.\n        unchecked {\n            address recoveredAddress = ecrecover(\n                keccak256(\n                    abi.encodePacked(\n                        \"\\x19\\x01\",\n                        DOMAIN_SEPARATOR(),\n                        keccak256(\n                            abi.encode(\n                                keccak256(\n                                    \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n                                ),\n                                owner,\n                                spender,\n                                value,\n                                nonces[owner]++,\n                                deadline\n                            )\n                        )\n                    )\n                ),\n                v,\n                r,\n                s\n            );\n\n            require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n            allowance[recoveredAddress][spender] = value;\n        }\n\n        emit Approval(owner, spender, value);\n    }\n\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n    }\n\n    function computeDomainSeparator() internal view virtual returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                    keccak256(bytes(name)),\n                    keccak256(\"1\"),\n                    block.chainid,\n                    address(this)\n                )\n            );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address to, uint256 amount) internal virtual {\n        totalSupply += amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(address(0), to, amount);\n    }\n\n    function _burn(address from, uint256 amount) internal virtual {\n        balanceOf[from] -= amount;\n\n        // Cannot underflow because a user's balance\n        // will never be larger than the total supply.\n        unchecked {\n            totalSupply -= amount;\n        }\n\n        emit Transfer(from, address(0), amount);\n    }\n}\n"
      },
      "lib/solmate/src/utils/SafeTransferLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\nimport {ERC20} from \"../tokens/ERC20.sol\";\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.\n/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*//////////////////////////////////////////////////////////////\n                             ETH OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferETH(address to, uint256 amount) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer the ETH and store if it succeeded or not.\n            success := call(gas(), to, amount, 0, 0, 0, 0)\n        }\n\n        require(success, \"ETH_TRANSFER_FAILED\");\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                            ERC20 OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function safeTransferFrom(\n        ERC20 token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"from\" argument.\n            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 68), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FROM_FAILED\");\n    }\n\n    function safeTransfer(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"TRANSFER_FAILED\");\n    }\n\n    function safeApprove(\n        ERC20 token,\n        address to,\n        uint256 amount\n    ) internal {\n        bool success;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Get a pointer to some free memory.\n            let freeMemoryPointer := mload(0x40)\n\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\n            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)\n            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the \"to\" argument.\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument. Masking not required as it's a full 32 byte type.\n\n            success := and(\n                // Set success to whether the call reverted, if not we check it either\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n                // Counterintuitively, this call must be positioned second to the or() call in the\n                // surrounding and() call or else returndatasize() will be zero during the computation.\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n            )\n        }\n\n        require(success, \"APPROVE_FAILED\");\n    }\n}\n"
      },
      "src/base/BoringVault.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport {Address} from \"@openzeppelin/contracts/utils/Address.sol\";\nimport {ERC721Holder} from \"@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol\";\nimport {ERC1155Holder} from \"@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol\";\nimport {FixedPointMathLib} from \"@solmate/utils/FixedPointMathLib.sol\";\nimport {SafeTransferLib} from \"@solmate/utils/SafeTransferLib.sol\";\nimport {ERC20} from \"@solmate/tokens/ERC20.sol\";\nimport {BeforeTransferHook} from \"src/interfaces/BeforeTransferHook.sol\";\nimport {Auth, Authority} from \"@solmate/auth/Auth.sol\";\n\ncontract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {\n    using Address for address;\n    using SafeTransferLib for ERC20;\n    using FixedPointMathLib for uint256;\n\n    // ========================================= STATE =========================================\n\n    /**\n     * @notice Contract responsbile for implementing `beforeTransfer`.\n     */\n    BeforeTransferHook public hook;\n\n    //============================== EVENTS ===============================\n\n    event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);\n    event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);\n\n    //============================== CONSTRUCTOR ===============================\n\n    constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)\n        ERC20(_name, _symbol, _decimals)\n        Auth(_owner, Authority(address(0)))\n    {}\n\n    //============================== MANAGE ===============================\n\n    /**\n     * @notice Allows manager to make an arbitrary function call from this contract.\n     * @dev Callable by MANAGER_ROLE.\n     */\n    function manage(address target, bytes calldata data, uint256 value)\n        external\n        requiresAuth\n        returns (bytes memory result)\n    {\n        result = target.functionCallWithValue(data, value);\n    }\n\n    /**\n     * @notice Allows manager to make arbitrary function calls from this contract.\n     * @dev Callable by MANAGER_ROLE.\n     */\n    function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)\n        external\n        requiresAuth\n        returns (bytes[] memory results)\n    {\n        uint256 targetsLength = targets.length;\n        results = new bytes[](targetsLength);\n        for (uint256 i; i < targetsLength; ++i) {\n            results[i] = targets[i].functionCallWithValue(data[i], values[i]);\n        }\n    }\n\n    //============================== ENTER ===============================\n\n    /**\n     * @notice Allows minter to mint shares, in exchange for assets.\n     * @dev If assetAmount is zero, no assets are transferred in.\n     * @dev Callable by MINTER_ROLE.\n     */\n    function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)\n        external\n        requiresAuth\n    {\n        // Transfer assets in\n        if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);\n\n        // Mint shares.\n        _mint(to, shareAmount);\n\n        emit Enter(from, address(asset), assetAmount, to, shareAmount);\n    }\n\n    //============================== EXIT ===============================\n\n    /**\n     * @notice Allows burner to burn shares, in exchange for assets.\n     * @dev If assetAmount is zero, no assets are transferred out.\n     * @dev Callable by BURNER_ROLE.\n     */\n    function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)\n        external\n        requiresAuth\n    {\n        // Burn shares.\n        _burn(from, shareAmount);\n\n        // Transfer assets out.\n        if (assetAmount > 0) asset.safeTransfer(to, assetAmount);\n\n        emit Exit(to, address(asset), assetAmount, from, shareAmount);\n    }\n\n    //============================== BEFORE TRANSFER HOOK ===============================\n    /**\n     * @notice Sets the share locker.\n     * @notice If set to zero address, the share locker logic is disabled.\n     * @dev Callable by OWNER_ROLE.\n     */\n    function setBeforeTransferHook(address _hook) external requiresAuth {\n        hook = BeforeTransferHook(_hook);\n    }\n\n    /**\n     * @notice Check if from addresses shares are locked, reverting if so.\n     */\n    function _callBeforeTransfer(address from) internal view {\n        if (address(hook) != address(0)) hook.beforeTransfer(from);\n    }\n\n    function transfer(address to, uint256 amount) public override returns (bool) {\n        _callBeforeTransfer(msg.sender);\n        return super.transfer(to, amount);\n    }\n\n    function transferFrom(address from, address to, uint256 amount) public override returns (bool) {\n        _callBeforeTransfer(from);\n        return super.transferFrom(from, to, amount);\n    }\n\n    //============================== RECEIVE ===============================\n\n    receive() external payable {}\n}\n"
      },
      "lib/solmate/src/auth/Auth.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)\n/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)\nabstract contract Auth {\n    event OwnershipTransferred(address indexed user, address indexed newOwner);\n\n    event AuthorityUpdated(address indexed user, Authority indexed newAuthority);\n\n    address public owner;\n\n    Authority public authority;\n\n    constructor(address _owner, Authority _authority) {\n        owner = _owner;\n        authority = _authority;\n\n        emit OwnershipTransferred(msg.sender, _owner);\n        emit AuthorityUpdated(msg.sender, _authority);\n    }\n\n    modifier requiresAuth() virtual {\n        require(isAuthorized(msg.sender, msg.sig), \"UNAUTHORIZED\");\n\n        _;\n    }\n\n    function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {\n        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.\n\n        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be\n        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.\n        return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;\n    }\n\n    function setAuthority(Authority newAuthority) public virtual {\n        // We check if the caller is the owner first because we want to ensure they can\n        // always swap out the authority even if it's reverting or using up a lot of gas.\n        require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));\n\n        authority = newAuthority;\n\n        emit AuthorityUpdated(msg.sender, newAuthority);\n    }\n\n    function transferOwnership(address newOwner) public virtual requiresAuth {\n        owner = newOwner;\n\n        emit OwnershipTransferred(msg.sender, newOwner);\n    }\n}\n\n/// @notice A generic interface for a contract which provides authorization data to an Auth instance.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)\n/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)\ninterface Authority {\n    function canCall(\n        address user,\n        address target,\n        bytes4 functionSig\n    ) external view returns (bool);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\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 or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\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    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\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    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) 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 FailedInnerCall();\n        }\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721Receiver} from \"../IERC721Receiver.sol\";\n\n/**\n * @dev Implementation of the {IERC721Receiver} interface.\n *\n * Accepts all token transfers.\n * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or\n * {IERC721-setApprovalForAll}.\n */\nabstract contract ERC721Holder is IERC721Receiver {\n    /**\n     * @dev See {IERC721Receiver-onERC721Received}.\n     *\n     * Always returns `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {\n        return this.onERC721Received.selector;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165, ERC165} from \"../../../utils/introspection/ERC165.sol\";\nimport {IERC1155Receiver} from \"../IERC1155Receiver.sol\";\n\n/**\n * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens.\n *\n * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be\n * stuck.\n */\nabstract contract ERC1155Holder is ERC165, IERC1155Receiver {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    function onERC1155Received(\n        address,\n        address,\n        uint256,\n        uint256,\n        bytes memory\n    ) public virtual override returns (bytes4) {\n        return this.onERC1155Received.selector;\n    }\n\n    function onERC1155BatchReceived(\n        address,\n        address,\n        uint256[] memory,\n        uint256[] memory,\n        bytes memory\n    ) public virtual override returns (bytes4) {\n        return this.onERC1155BatchReceived.selector;\n    }\n}\n"
      },
      "src/interfaces/BeforeTransferHook.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface BeforeTransferHook {\n    function beforeTransfer(address from) external view;\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Interface that must be implemented by smart contracts in order to receive\n * ERC-1155 token transfers.\n */\ninterface IERC1155Receiver is IERC165 {\n    /**\n     * @dev Handles the receipt of a single ERC1155 token type. This function is\n     * called at the end of a `safeTransferFrom` after the balance has been updated.\n     *\n     * NOTE: To accept the transfer, this must return\n     * `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n     * (i.e. 0xf23a6e61, or its own function selector).\n     *\n     * @param operator The address which initiated the transfer (i.e. msg.sender)\n     * @param from The address which previously owned the token\n     * @param id The ID of the token being transferred\n     * @param value The amount of tokens being transferred\n     * @param data Additional data with no specified format\n     * @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` if transfer is allowed\n     */\n    function onERC1155Received(\n        address operator,\n        address from,\n        uint256 id,\n        uint256 value,\n        bytes calldata data\n    ) external returns (bytes4);\n\n    /**\n     * @dev Handles the receipt of a multiple ERC1155 token types. This function\n     * is called at the end of a `safeBatchTransferFrom` after the balances have\n     * been updated.\n     *\n     * NOTE: To accept the transfer(s), this must return\n     * `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n     * (i.e. 0xbc197c81, or its own function selector).\n     *\n     * @param operator The address which initiated the batch transfer (i.e. msg.sender)\n     * @param from The address which previously owned the token\n     * @param ids An array containing ids of each token being transferred (order and length must match values array)\n     * @param values An array containing amounts of each token being transferred (order and length must match ids array)\n     * @param data Additional data with no specified format\n     * @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` if transfer is allowed\n     */\n    function onERC1155BatchReceived(\n        address operator,\n        address from,\n        uint256[] calldata ids,\n        uint256[] calldata values,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@solmate/=lib/solmate/src/",
        "@forge-std/=lib/forge-std/src/",
        "@ds-test/=lib/forge-std/lib/ds-test/src/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@ion-protocol/=lib/ion-protocol/src/",
        "@balancer-labs/v2-interfaces/=lib/ion-protocol/lib/balancer-v2-monorepo/pkg/interfaces/",
        "@balancer-labs/v2-pool-stable/=lib/ion-protocol/lib/balancer-v2-monorepo/pkg/pool-stable/",
        "@chainlink/contracts/=lib/ion-protocol/lib/chainlink/contracts/",
        "@openzeppelin/contracts-upgradeable/=lib/ion-protocol/lib/openzeppelin-contracts-upgradeable/contracts/",
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "@uniswap/v3-core/=lib/ion-protocol/lib/v3-core/",
        "@uniswap/v3-periphery/=lib/ion-protocol/lib/v3-periphery/",
        "balancer-v2-monorepo/=lib/ion-protocol/lib/",
        "chainlink/=lib/ion-protocol/lib/chainlink/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "forge-safe/=lib/ion-protocol/lib/forge-safe/",
        "forge-std/=lib/forge-std/src/",
        "ion-protocol/=lib/ion-protocol/",
        "openzeppelin-contracts-upgradeable/=lib/ion-protocol/lib/openzeppelin-contracts-upgradeable/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "pendle-core-v2-public/=lib/ion-protocol/lib/pendle-core-v2-public/contracts/",
        "solady/=lib/ion-protocol/lib/solady/",
        "solarray/=lib/ion-protocol/lib/solarray/src/",
        "solidity-stringutils/=lib/ion-protocol/lib/forge-safe/lib/surl/lib/solidity-stringutils/",
        "solmate/=lib/solmate/src/",
        "surl/=lib/ion-protocol/lib/forge-safe/lib/surl/",
        "v3-core/=lib/ion-protocol/lib/v3-core/",
        "v3-periphery/=lib/ion-protocol/lib/v3-periphery/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "shanghai",
      "viaIR": false,
      "libraries": {}
    }
  }}