creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@morpho-org/morpho-blue/src/interfaces/IMorpho.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\ntype Id is bytes32;\n\nstruct MarketParams {\n    address loanToken;\n    address collateralToken;\n    address oracle;\n    address irm;\n    uint256 lltv;\n}\n\n/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest\n/// accrual.\nstruct Position {\n    uint256 supplyShares;\n    uint128 borrowShares;\n    uint128 collateral;\n}\n\n/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.\n/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.\n/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last\n/// interest accrual.\nstruct Market {\n    uint128 totalSupplyAssets;\n    uint128 totalSupplyShares;\n    uint128 totalBorrowAssets;\n    uint128 totalBorrowShares;\n    uint128 lastUpdate;\n    uint128 fee;\n}\n\nstruct Authorization {\n    address authorizer;\n    address authorized;\n    bool isAuthorized;\n    uint256 nonce;\n    uint256 deadline;\n}\n\nstruct Signature {\n    uint8 v;\n    bytes32 r;\n    bytes32 s;\n}\n\n/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.\n/// @dev Consider using the IMorpho interface instead of this one.\ninterface IMorphoBase {\n    /// @notice The EIP-712 domain separator.\n    /// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing\n    /// the same chain id because the domain separator would be the same.\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    /// @notice The owner of the contract.\n    /// @dev It has the power to change the owner.\n    /// @dev It has the power to set fees on markets and set the fee recipient.\n    /// @dev It has the power to enable but not disable IRMs and LLTVs.\n    function owner() external view returns (address);\n\n    /// @notice The fee recipient of all markets.\n    /// @dev The recipient receives the fees of a given market through a supply position on that market.\n    function feeRecipient() external view returns (address);\n\n    /// @notice Whether the `irm` is enabled.\n    function isIrmEnabled(address irm) external view returns (bool);\n\n    /// @notice Whether the `lltv` is enabled.\n    function isLltvEnabled(uint256 lltv) external view returns (bool);\n\n    /// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.\n    /// @dev Anyone is authorized to modify their own positions, regardless of this variable.\n    function isAuthorized(address authorizer, address authorized) external view returns (bool);\n\n    /// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.\n    function nonce(address authorizer) external view returns (uint256);\n\n    /// @notice Sets `newOwner` as `owner` of the contract.\n    /// @dev Warning: No two-step transfer ownership.\n    /// @dev Warning: The owner can be set to the zero address.\n    function setOwner(address newOwner) external;\n\n    /// @notice Enables `irm` as a possible IRM for market creation.\n    /// @dev Warning: It is not possible to disable an IRM.\n    function enableIrm(address irm) external;\n\n    /// @notice Enables `lltv` as a possible LLTV for market creation.\n    /// @dev Warning: It is not possible to disable a LLTV.\n    function enableLltv(uint256 lltv) external;\n\n    /// @notice Sets the `newFee` for the given market `marketParams`.\n    /// @param newFee The new fee, scaled by WAD.\n    /// @dev Warning: The recipient can be the zero address.\n    function setFee(MarketParams memory marketParams, uint256 newFee) external;\n\n    /// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.\n    /// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.\n    /// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To\n    /// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.\n    function setFeeRecipient(address newFeeRecipient) external;\n\n    /// @notice Creates the market `marketParams`.\n    /// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees\n    /// Morpho behaves as expected:\n    /// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.\n    /// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with\n    /// burn functions are not supported.\n    /// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.\n    /// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount\n    /// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.\n    /// - The IRM should not re-enter Morpho.\n    /// - The oracle should return a price with the correct scaling.\n    /// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties\n    /// (funds could get stuck):\n    /// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.\n    /// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and\n    /// `toSharesDown` overflow.\n    /// - The IRM can revert on `borrowRate`.\n    /// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`\n    /// overflow.\n    /// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and\n    /// `liquidate` from being used under certain market conditions.\n    /// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or\n    /// the computation of `assetsRepaid` in `liquidate` overflow.\n    /// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to\n    /// the point where `totalBorrowShares` is very large and borrowing overflows.\n    function createMarket(MarketParams memory marketParams) external;\n\n    /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's\n    /// `onMorphoSupply` function with the given `data`.\n    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the\n    /// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific\n    /// amount of shares is given for full compatibility and precision.\n    /// @dev Supplying a large amount can revert for overflow.\n    /// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.\n    /// Consider using the `assets` parameter to avoid this.\n    /// @param marketParams The market to supply assets to.\n    /// @param assets The amount of assets to supply.\n    /// @param shares The amount of shares to mint.\n    /// @param onBehalf The address that will own the increased supply position.\n    /// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.\n    /// @return assetsSupplied The amount of assets supplied.\n    /// @return sharesSupplied The amount of shares minted.\n    function supply(\n        MarketParams memory marketParams,\n        uint256 assets,\n        uint256 shares,\n        address onBehalf,\n        bytes memory data\n    ) external returns (uint256 assetsSupplied, uint256 sharesSupplied);\n\n    /// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.\n    /// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.\n    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.\n    /// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.\n    /// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to\n    /// conversion roundings between shares and assets.\n    /// @param marketParams The market to withdraw assets from.\n    /// @param assets The amount of assets to withdraw.\n    /// @param shares The amount of shares to burn.\n    /// @param onBehalf The address of the owner of the supply position.\n    /// @param receiver The address that will receive the withdrawn assets.\n    /// @return assetsWithdrawn The amount of assets withdrawn.\n    /// @return sharesWithdrawn The amount of shares burned.\n    function withdraw(\n        MarketParams memory marketParams,\n        uint256 assets,\n        uint256 shares,\n        address onBehalf,\n        address receiver\n    ) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);\n\n    /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.\n    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the\n    /// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is\n    /// given for full compatibility and precision.\n    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.\n    /// @dev Borrowing a large amount can revert for overflow.\n    /// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.\n    /// Consider using the `assets` parameter to avoid this.\n    /// @param marketParams The market to borrow assets from.\n    /// @param assets The amount of assets to borrow.\n    /// @param shares The amount of shares to mint.\n    /// @param onBehalf The address that will own the increased borrow position.\n    /// @param receiver The address that will receive the borrowed assets.\n    /// @return assetsBorrowed The amount of assets borrowed.\n    /// @return sharesBorrowed The amount of shares minted.\n    function borrow(\n        MarketParams memory marketParams,\n        uint256 assets,\n        uint256 shares,\n        address onBehalf,\n        address receiver\n    ) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);\n\n    /// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's\n    /// `onMorphoReplay` function with the given `data`.\n    /// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.\n    /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.\n    /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion\n    /// roundings between shares and assets.\n    /// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.\n    /// @param marketParams The market to repay assets to.\n    /// @param assets The amount of assets to repay.\n    /// @param shares The amount of shares to burn.\n    /// @param onBehalf The address of the owner of the debt position.\n    /// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.\n    /// @return assetsRepaid The amount of assets repaid.\n    /// @return sharesRepaid The amount of shares burned.\n    function repay(\n        MarketParams memory marketParams,\n        uint256 assets,\n        uint256 shares,\n        address onBehalf,\n        bytes memory data\n    ) external returns (uint256 assetsRepaid, uint256 sharesRepaid);\n\n    /// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's\n    /// `onMorphoSupplyCollateral` function with the given `data`.\n    /// @dev Interest are not accrued since it's not required and it saves gas.\n    /// @dev Supplying a large amount can revert for overflow.\n    /// @param marketParams The market to supply collateral to.\n    /// @param assets The amount of collateral to supply.\n    /// @param onBehalf The address that will own the increased collateral position.\n    /// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.\n    function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)\n        external;\n\n    /// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.\n    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.\n    /// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.\n    /// @param marketParams The market to withdraw collateral from.\n    /// @param assets The amount of collateral to withdraw.\n    /// @param onBehalf The address of the owner of the collateral position.\n    /// @param receiver The address that will receive the collateral assets.\n    function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)\n        external;\n\n    /// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the\n    /// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's\n    /// `onMorphoLiquidate` function with the given `data`.\n    /// @dev Either `seizedAssets` or `repaidShares` should be zero.\n    /// @dev Seizing more than the collateral balance will underflow and revert without any error message.\n    /// @dev Repaying more than the borrow balance will underflow and revert without any error message.\n    /// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.\n    /// @param marketParams The market of the position.\n    /// @param borrower The owner of the position.\n    /// @param seizedAssets The amount of collateral to seize.\n    /// @param repaidShares The amount of shares to repay.\n    /// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.\n    /// @return The amount of assets seized.\n    /// @return The amount of assets repaid.\n    function liquidate(\n        MarketParams memory marketParams,\n        address borrower,\n        uint256 seizedAssets,\n        uint256 repaidShares,\n        bytes memory data\n    ) external returns (uint256, uint256);\n\n    /// @notice Executes a flash loan.\n    /// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all\n    /// markets combined, plus donations).\n    /// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:\n    /// - `flashFee` is zero.\n    /// - `maxFlashLoan` is the token's balance of this contract.\n    /// - The receiver of `assets` is the caller.\n    /// @param token The token to flash loan.\n    /// @param assets The amount of assets to flash loan.\n    /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.\n    function flashLoan(address token, uint256 assets, bytes calldata data) external;\n\n    /// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.\n    /// @param authorized The authorized address.\n    /// @param newIsAuthorized The new authorization status.\n    function setAuthorization(address authorized, bool newIsAuthorized) external;\n\n    /// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.\n    /// @dev Warning: Reverts if the signature has already been submitted.\n    /// @dev The signature is malleable, but it has no impact on the security here.\n    /// @dev The nonce is passed as argument to be able to revert with a different error message.\n    /// @param authorization The `Authorization` struct.\n    /// @param signature The signature.\n    function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;\n\n    /// @notice Accrues interest for the given market `marketParams`.\n    function accrueInterest(MarketParams memory marketParams) external;\n\n    /// @notice Returns the data stored on the different `slots`.\n    function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);\n}\n\n/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.\n/// @dev Consider using the IMorpho interface instead of this one.\ninterface IMorphoStaticTyping is IMorphoBase {\n    /// @notice The state of the position of `user` on the market corresponding to `id`.\n    /// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest\n    /// accrual.\n    function position(Id id, address user)\n        external\n        view\n        returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);\n\n    /// @notice The state of the market corresponding to `id`.\n    /// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.\n    /// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.\n    /// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest\n    /// accrual.\n    function market(Id id)\n        external\n        view\n        returns (\n            uint128 totalSupplyAssets,\n            uint128 totalSupplyShares,\n            uint128 totalBorrowAssets,\n            uint128 totalBorrowShares,\n            uint128 lastUpdate,\n            uint128 fee\n        );\n\n    /// @notice The market params corresponding to `id`.\n    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer\n    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.\n    function idToMarketParams(Id id)\n        external\n        view\n        returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);\n}\n\n/// @title IMorpho\n/// @author Morpho Labs\n/// @custom:contact security@morpho.org\n/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.\ninterface IMorpho is IMorphoBase {\n    /// @notice The state of the position of `user` on the market corresponding to `id`.\n    /// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest\n    /// accrual.\n    function position(Id id, address user) external view returns (Position memory p);\n\n    /// @notice The state of the market corresponding to `id`.\n    /// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.\n    /// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.\n    /// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last\n    /// interest accrual.\n    function market(Id id) external view returns (Market memory m);\n\n    /// @notice The market params corresponding to `id`.\n    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer\n    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.\n    function idToMarketParams(Id id) external view returns (MarketParams memory);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n// EIP-2612 is Final as of 2022-11-01. This file is deprecated.\n\nimport \"./IERC20Permit.sol\";\n"
      },
      "@openzeppelin/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"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/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"
      },
      "@openzeppelin/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"
      },
      "@openzeppelin/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"
      },
      "@prb/math/src/Common.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.19;\n\n// Common.sol\n//\n// Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not\n// always operate with SD59x18 and UD60x18 numbers.\n\n/*//////////////////////////////////////////////////////////////////////////\n                                CUSTOM ERRORS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.\nerror PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);\n\n/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.\nerror PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);\n\n/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.\nerror PRBMath_MulDivSigned_InputTooSmall();\n\n/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.\nerror PRBMath_MulDivSigned_Overflow(int256 x, int256 y);\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    CONSTANTS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @dev The maximum value a uint128 number can have.\nuint128 constant MAX_UINT128 = type(uint128).max;\n\n/// @dev The maximum value a uint40 number can have.\nuint40 constant MAX_UINT40 = type(uint40).max;\n\n/// @dev The unit number, which the decimal precision of the fixed-point types.\nuint256 constant UNIT = 1e18;\n\n/// @dev The unit number inverted mod 2^256.\nuint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant\n/// bit in the binary representation of `UNIT`.\nuint256 constant UNIT_LPOTD = 262144;\n\n/*//////////////////////////////////////////////////////////////////////////\n                                    FUNCTIONS\n//////////////////////////////////////////////////////////////////////////*/\n\n/// @notice Calculates the binary exponent of x using the binary fraction method.\n/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.\n/// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n/// @return result The result as an unsigned 60.18-decimal fixed-point number.\n/// @custom:smtchecker abstract-function-nondet\nfunction exp2(uint256 x) pure returns (uint256 result) {\n    unchecked {\n        // Start from 0.5 in the 192.64-bit fixed-point format.\n        result = 0x800000000000000000000000000000000000000000000000;\n\n        // The following logic multiplies the result by $\\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:\n        //\n        // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.\n        // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing\n        // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,\n        // we know that `x & 0xFF` is also 1.\n        if (x & 0xFF00000000000000 > 0) {\n            if (x & 0x8000000000000000 > 0) {\n                result = (result * 0x16A09E667F3BCC909) >> 64;\n            }\n            if (x & 0x4000000000000000 > 0) {\n                result = (result * 0x1306FE0A31B7152DF) >> 64;\n            }\n            if (x & 0x2000000000000000 > 0) {\n                result = (result * 0x1172B83C7D517ADCE) >> 64;\n            }\n            if (x & 0x1000000000000000 > 0) {\n                result = (result * 0x10B5586CF9890F62A) >> 64;\n            }\n            if (x & 0x800000000000000 > 0) {\n                result = (result * 0x1059B0D31585743AE) >> 64;\n            }\n            if (x & 0x400000000000000 > 0) {\n                result = (result * 0x102C9A3E778060EE7) >> 64;\n            }\n            if (x & 0x200000000000000 > 0) {\n                result = (result * 0x10163DA9FB33356D8) >> 64;\n            }\n            if (x & 0x100000000000000 > 0) {\n                result = (result * 0x100B1AFA5ABCBED61) >> 64;\n            }\n        }\n\n        if (x & 0xFF000000000000 > 0) {\n            if (x & 0x80000000000000 > 0) {\n                result = (result * 0x10058C86DA1C09EA2) >> 64;\n            }\n            if (x & 0x40000000000000 > 0) {\n                result = (result * 0x1002C605E2E8CEC50) >> 64;\n            }\n            if (x & 0x20000000000000 > 0) {\n                result = (result * 0x100162F3904051FA1) >> 64;\n            }\n            if (x & 0x10000000000000 > 0) {\n                result = (result * 0x1000B175EFFDC76BA) >> 64;\n            }\n            if (x & 0x8000000000000 > 0) {\n                result = (result * 0x100058BA01FB9F96D) >> 64;\n            }\n            if (x & 0x4000000000000 > 0) {\n                result = (result * 0x10002C5CC37DA9492) >> 64;\n            }\n            if (x & 0x2000000000000 > 0) {\n                result = (result * 0x1000162E525EE0547) >> 64;\n            }\n            if (x & 0x1000000000000 > 0) {\n                result = (result * 0x10000B17255775C04) >> 64;\n            }\n        }\n\n        if (x & 0xFF0000000000 > 0) {\n            if (x & 0x800000000000 > 0) {\n                result = (result * 0x1000058B91B5BC9AE) >> 64;\n            }\n            if (x & 0x400000000000 > 0) {\n                result = (result * 0x100002C5C89D5EC6D) >> 64;\n            }\n            if (x & 0x200000000000 > 0) {\n                result = (result * 0x10000162E43F4F831) >> 64;\n            }\n            if (x & 0x100000000000 > 0) {\n                result = (result * 0x100000B1721BCFC9A) >> 64;\n            }\n            if (x & 0x80000000000 > 0) {\n                result = (result * 0x10000058B90CF1E6E) >> 64;\n            }\n            if (x & 0x40000000000 > 0) {\n                result = (result * 0x1000002C5C863B73F) >> 64;\n            }\n            if (x & 0x20000000000 > 0) {\n                result = (result * 0x100000162E430E5A2) >> 64;\n            }\n            if (x & 0x10000000000 > 0) {\n                result = (result * 0x1000000B172183551) >> 64;\n            }\n        }\n\n        if (x & 0xFF00000000 > 0) {\n            if (x & 0x8000000000 > 0) {\n                result = (result * 0x100000058B90C0B49) >> 64;\n            }\n            if (x & 0x4000000000 > 0) {\n                result = (result * 0x10000002C5C8601CC) >> 64;\n            }\n            if (x & 0x2000000000 > 0) {\n                result = (result * 0x1000000162E42FFF0) >> 64;\n            }\n            if (x & 0x1000000000 > 0) {\n                result = (result * 0x10000000B17217FBB) >> 64;\n            }\n            if (x & 0x800000000 > 0) {\n                result = (result * 0x1000000058B90BFCE) >> 64;\n            }\n            if (x & 0x400000000 > 0) {\n                result = (result * 0x100000002C5C85FE3) >> 64;\n            }\n            if (x & 0x200000000 > 0) {\n                result = (result * 0x10000000162E42FF1) >> 64;\n            }\n            if (x & 0x100000000 > 0) {\n                result = (result * 0x100000000B17217F8) >> 64;\n            }\n        }\n\n        if (x & 0xFF000000 > 0) {\n            if (x & 0x80000000 > 0) {\n                result = (result * 0x10000000058B90BFC) >> 64;\n            }\n            if (x & 0x40000000 > 0) {\n                result = (result * 0x1000000002C5C85FE) >> 64;\n            }\n            if (x & 0x20000000 > 0) {\n                result = (result * 0x100000000162E42FF) >> 64;\n            }\n            if (x & 0x10000000 > 0) {\n                result = (result * 0x1000000000B17217F) >> 64;\n            }\n            if (x & 0x8000000 > 0) {\n                result = (result * 0x100000000058B90C0) >> 64;\n            }\n            if (x & 0x4000000 > 0) {\n                result = (result * 0x10000000002C5C860) >> 64;\n            }\n            if (x & 0x2000000 > 0) {\n                result = (result * 0x1000000000162E430) >> 64;\n            }\n            if (x & 0x1000000 > 0) {\n                result = (result * 0x10000000000B17218) >> 64;\n            }\n        }\n\n        if (x & 0xFF0000 > 0) {\n            if (x & 0x800000 > 0) {\n                result = (result * 0x1000000000058B90C) >> 64;\n            }\n            if (x & 0x400000 > 0) {\n                result = (result * 0x100000000002C5C86) >> 64;\n            }\n            if (x & 0x200000 > 0) {\n                result = (result * 0x10000000000162E43) >> 64;\n            }\n            if (x & 0x100000 > 0) {\n                result = (result * 0x100000000000B1721) >> 64;\n            }\n            if (x & 0x80000 > 0) {\n                result = (result * 0x10000000000058B91) >> 64;\n            }\n            if (x & 0x40000 > 0) {\n                result = (result * 0x1000000000002C5C8) >> 64;\n            }\n            if (x & 0x20000 > 0) {\n                result = (result * 0x100000000000162E4) >> 64;\n            }\n            if (x & 0x10000 > 0) {\n                result = (result * 0x1000000000000B172) >> 64;\n            }\n        }\n\n        if (x & 0xFF00 > 0) {\n            if (x & 0x8000 > 0) {\n                result = (result * 0x100000000000058B9) >> 64;\n            }\n            if (x & 0x4000 > 0) {\n                result = (result * 0x10000000000002C5D) >> 64;\n            }\n            if (x & 0x2000 > 0) {\n                result = (result * 0x1000000000000162E) >> 64;\n            }\n            if (x & 0x1000 > 0) {\n                result = (result * 0x10000000000000B17) >> 64;\n            }\n            if (x & 0x800 > 0) {\n                result = (result * 0x1000000000000058C) >> 64;\n            }\n            if (x & 0x400 > 0) {\n                result = (result * 0x100000000000002C6) >> 64;\n            }\n            if (x & 0x200 > 0) {\n                result = (result * 0x10000000000000163) >> 64;\n            }\n            if (x & 0x100 > 0) {\n                result = (result * 0x100000000000000B1) >> 64;\n            }\n        }\n\n        if (x & 0xFF > 0) {\n            if (x & 0x80 > 0) {\n                result = (result * 0x10000000000000059) >> 64;\n            }\n            if (x & 0x40 > 0) {\n                result = (result * 0x1000000000000002C) >> 64;\n            }\n            if (x & 0x20 > 0) {\n                result = (result * 0x10000000000000016) >> 64;\n            }\n            if (x & 0x10 > 0) {\n                result = (result * 0x1000000000000000B) >> 64;\n            }\n            if (x & 0x8 > 0) {\n                result = (result * 0x10000000000000006) >> 64;\n            }\n            if (x & 0x4 > 0) {\n                result = (result * 0x10000000000000003) >> 64;\n            }\n            if (x & 0x2 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n            if (x & 0x1 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n        }\n\n        // In the code snippet below, two operations are executed simultaneously:\n        //\n        // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1\n        // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.\n        // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.\n        //\n        // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,\n        // integer part, $2^n$.\n        result *= UNIT;\n        result >>= (191 - (x >> 64));\n    }\n}\n\n/// @notice Finds the zero-based index of the first 1 in the binary representation of x.\n///\n/// @dev See the note on \"msb\" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set\n///\n/// Each step in this implementation is equivalent to this high-level code:\n///\n/// ```solidity\n/// if (x >= 2 ** 128) {\n///     x >>= 128;\n///     result += 128;\n/// }\n/// ```\n///\n/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:\n/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948\n///\n/// The Yul instructions used below are:\n///\n/// - \"gt\" is \"greater than\"\n/// - \"or\" is the OR bitwise operator\n/// - \"shl\" is \"shift left\"\n/// - \"shr\" is \"shift right\"\n///\n/// @param x The uint256 number for which to find the index of the most significant bit.\n/// @return result The index of the most significant bit as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction msb(uint256 x) pure returns (uint256 result) {\n    // 2^128\n    assembly (\"memory-safe\") {\n        let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^64\n    assembly (\"memory-safe\") {\n        let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^32\n    assembly (\"memory-safe\") {\n        let factor := shl(5, gt(x, 0xFFFFFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^16\n    assembly (\"memory-safe\") {\n        let factor := shl(4, gt(x, 0xFFFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^8\n    assembly (\"memory-safe\") {\n        let factor := shl(3, gt(x, 0xFF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^4\n    assembly (\"memory-safe\") {\n        let factor := shl(2, gt(x, 0xF))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^2\n    assembly (\"memory-safe\") {\n        let factor := shl(1, gt(x, 0x3))\n        x := shr(factor, x)\n        result := or(result, factor)\n    }\n    // 2^1\n    // No need to shift x any more.\n    assembly (\"memory-safe\") {\n        let factor := gt(x, 0x1)\n        result := or(result, factor)\n    }\n}\n\n/// @notice Calculates x*y÷denominator with 512-bit precision.\n///\n/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n///\n/// Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - The denominator must not be zero.\n/// - The result must fit in uint256.\n///\n/// @param x The multiplicand as a uint256.\n/// @param y The multiplier as a uint256.\n/// @param denominator The divisor as a uint256.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {\n    // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n    // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256\n    // variables such that product = prod1 * 2^256 + prod0.\n    uint256 prod0; // Least significant 256 bits of the product\n    uint256 prod1; // Most significant 256 bits of the product\n    assembly (\"memory-safe\") {\n        let mm := mulmod(x, y, not(0))\n        prod0 := mul(x, y)\n        prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n    }\n\n    // Handle non-overflow cases, 256 by 256 division.\n    if (prod1 == 0) {\n        unchecked {\n            return prod0 / denominator;\n        }\n    }\n\n    // Make sure the result is less than 2^256. Also prevents denominator == 0.\n    if (prod1 >= denominator) {\n        revert PRBMath_MulDiv_Overflow(x, y, denominator);\n    }\n\n    ////////////////////////////////////////////////////////////////////////////\n    // 512 by 256 division\n    ////////////////////////////////////////////////////////////////////////////\n\n    // Make division exact by subtracting the remainder from [prod1 prod0].\n    uint256 remainder;\n    assembly (\"memory-safe\") {\n        // Compute remainder using the mulmod Yul instruction.\n        remainder := mulmod(x, y, denominator)\n\n        // Subtract 256 bit number from 512-bit number.\n        prod1 := sub(prod1, gt(remainder, prod0))\n        prod0 := sub(prod0, remainder)\n    }\n\n    unchecked {\n        // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow\n        // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.\n        // For more detail, see https://cs.stackexchange.com/q/138556/92363.\n        uint256 lpotdod = denominator & (~denominator + 1);\n        uint256 flippedLpotdod;\n\n        assembly (\"memory-safe\") {\n            // Factor powers of two out of denominator.\n            denominator := div(denominator, lpotdod)\n\n            // Divide [prod1 prod0] by lpotdod.\n            prod0 := div(prod0, lpotdod)\n\n            // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.\n            // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.\n            // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693\n            flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n        }\n\n        // Shift in bits from prod1 into prod0.\n        prod0 |= prod1 * flippedLpotdod;\n\n        // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n        // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n        // four bits. That is, denominator * inv = 1 mod 2^4.\n        uint256 inverse = (3 * denominator) ^ 2;\n\n        // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n        // in modular arithmetic, doubling the correct bits in each step.\n        inverse *= 2 - denominator * inverse; // inverse mod 2^8\n        inverse *= 2 - denominator * inverse; // inverse mod 2^16\n        inverse *= 2 - denominator * inverse; // inverse mod 2^32\n        inverse *= 2 - denominator * inverse; // inverse mod 2^64\n        inverse *= 2 - denominator * inverse; // inverse mod 2^128\n        inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n        // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n        // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n        // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n        // is no longer required.\n        result = prod0 * inverse;\n    }\n}\n\n/// @notice Calculates x*y÷1e18 with 512-bit precision.\n///\n/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.\n///\n/// Notes:\n/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.\n/// - The result is rounded toward zero.\n/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:\n///\n/// $$\n/// \\begin{cases}\n///     x * y = MAX\\_UINT256 * UNIT \\\\\n///     (x * y) \\% UNIT \\geq \\frac{UNIT}{2}\n/// \\end{cases}\n/// $$\n///\n/// Requirements:\n/// - Refer to the requirements in {mulDiv}.\n/// - The result must fit in uint256.\n///\n/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n/// @return result The result as an unsigned 60.18-decimal fixed-point number.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {\n    uint256 prod0;\n    uint256 prod1;\n    assembly (\"memory-safe\") {\n        let mm := mulmod(x, y, not(0))\n        prod0 := mul(x, y)\n        prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n    }\n\n    if (prod1 == 0) {\n        unchecked {\n            return prod0 / UNIT;\n        }\n    }\n\n    if (prod1 >= UNIT) {\n        revert PRBMath_MulDiv18_Overflow(x, y);\n    }\n\n    uint256 remainder;\n    assembly (\"memory-safe\") {\n        remainder := mulmod(x, y, UNIT)\n        result :=\n            mul(\n                or(\n                    div(sub(prod0, remainder), UNIT_LPOTD),\n                    mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))\n                ),\n                UNIT_INVERSE\n            )\n    }\n}\n\n/// @notice Calculates x*y÷denominator with 512-bit precision.\n///\n/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.\n///\n/// Notes:\n/// - The result is rounded toward zero.\n///\n/// Requirements:\n/// - Refer to the requirements in {mulDiv}.\n/// - None of the inputs can be `type(int256).min`.\n/// - The result must fit in int256.\n///\n/// @param x The multiplicand as an int256.\n/// @param y The multiplier as an int256.\n/// @param denominator The divisor as an int256.\n/// @return result The result as an int256.\n/// @custom:smtchecker abstract-function-nondet\nfunction mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {\n    if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n        revert PRBMath_MulDivSigned_InputTooSmall();\n    }\n\n    // Get hold of the absolute values of x, y and the denominator.\n    uint256 xAbs;\n    uint256 yAbs;\n    uint256 dAbs;\n    unchecked {\n        xAbs = x < 0 ? uint256(-x) : uint256(x);\n        yAbs = y < 0 ? uint256(-y) : uint256(y);\n        dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n    }\n\n    // Compute the absolute value of x*y÷denominator. The result must fit in int256.\n    uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);\n    if (resultAbs > uint256(type(int256).max)) {\n        revert PRBMath_MulDivSigned_Overflow(x, y);\n    }\n\n    // Get the signs of x, y and the denominator.\n    uint256 sx;\n    uint256 sy;\n    uint256 sd;\n    assembly (\"memory-safe\") {\n        // \"sgt\" is the \"signed greater than\" assembly instruction and \"sub(0,1)\" is -1 in two's complement.\n        sx := sgt(x, sub(0, 1))\n        sy := sgt(y, sub(0, 1))\n        sd := sgt(denominator, sub(0, 1))\n    }\n\n    // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.\n    // If there are, the result should be negative. Otherwise, it should be positive.\n    unchecked {\n        result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);\n    }\n}\n\n/// @notice Calculates the square root of x using the Babylonian method.\n///\n/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n///\n/// Notes:\n/// - If x is not a perfect square, the result is rounded down.\n/// - Credits to OpenZeppelin for the explanations in comments below.\n///\n/// @param x The uint256 number for which to calculate the square root.\n/// @return result The result as a uint256.\n/// @custom:smtchecker abstract-function-nondet\nfunction sqrt(uint256 x) pure returns (uint256 result) {\n    if (x == 0) {\n        return 0;\n    }\n\n    // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.\n    //\n    // We know that the \"msb\" (most significant bit) of x is a power of 2 such that we have:\n    //\n    // $$\n    // msb(x) <= x <= 2*msb(x)$\n    // $$\n    //\n    // We write $msb(x)$ as $2^k$, and we get:\n    //\n    // $$\n    // k = log_2(x)\n    // $$\n    //\n    // Thus, we can write the initial inequality as:\n    //\n    // $$\n    // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\\n    // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\\n    // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}\n    // $$\n    //\n    // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.\n    uint256 xAux = uint256(x);\n    result = 1;\n    if (xAux >= 2 ** 128) {\n        xAux >>= 128;\n        result <<= 64;\n    }\n    if (xAux >= 2 ** 64) {\n        xAux >>= 64;\n        result <<= 32;\n    }\n    if (xAux >= 2 ** 32) {\n        xAux >>= 32;\n        result <<= 16;\n    }\n    if (xAux >= 2 ** 16) {\n        xAux >>= 16;\n        result <<= 8;\n    }\n    if (xAux >= 2 ** 8) {\n        xAux >>= 8;\n        result <<= 4;\n    }\n    if (xAux >= 2 ** 4) {\n        xAux >>= 4;\n        result <<= 2;\n    }\n    if (xAux >= 2 ** 2) {\n        result <<= 1;\n    }\n\n    // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at\n    // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision\n    // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of\n    // precision into the expected uint128 result.\n    unchecked {\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n        result = (result + x / result) >> 1;\n\n        // If x is not a perfect square, round the result toward zero.\n        uint256 roundedResult = x / result;\n        if (result >= roundedResult) {\n            result = roundedResult;\n        }\n    }\n}\n"
      },
      "contracts/common/access/OrigamiElevatedAccess.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (common/access/OrigamiElevatedAccessBase.sol)\n\nimport { OrigamiElevatedAccessBase } from \"contracts/common/access/OrigamiElevatedAccessBase.sol\";\n\n/**\n * @notice Inherit to add Owner roles for DAO elevated access.\n */ \nabstract contract OrigamiElevatedAccess is OrigamiElevatedAccessBase {\n    constructor(address initialOwner) {\n        _init(initialOwner);\n    }\n}\n"
      },
      "contracts/common/access/OrigamiElevatedAccessBase.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (common/access/OrigamiElevatedAccessBase.sol)\n\nimport { IOrigamiElevatedAccess } from \"contracts/interfaces/common/access/IOrigamiElevatedAccess.sol\";\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\n\n/**\n * @notice Inherit to add Owner roles for DAO elevated access.\n */ \nabstract contract OrigamiElevatedAccessBase is IOrigamiElevatedAccess {\n    /**\n     * @notice The address of the current owner.\n     */ \n    address public override owner;\n\n    /**\n     * @notice Explicit approval for an address to execute a function.\n     * allowedCaller => function selector => true/false\n     */\n    mapping(address => mapping(bytes4 => bool)) public override explicitFunctionAccess;\n\n    /// @dev Track proposed owner\n    address private _proposedNewOwner;\n\n    function _init(address initialOwner) internal {\n        if (owner != address(0)) revert CommonEventsAndErrors.InvalidAccess();\n        if (initialOwner == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0));\n        owner = initialOwner;\n    }\n\n    /**\n     * @notice Proposes a new Owner.\n     * Can only be called by the current owner\n     */\n    function proposeNewOwner(address account) external override onlyElevatedAccess {\n        if (account == address(0)) revert CommonEventsAndErrors.InvalidAddress(account);\n        emit NewOwnerProposed(owner, _proposedNewOwner, account);\n        _proposedNewOwner = account;\n    }\n\n    /**\n     * @notice Caller accepts the role as new Owner.\n     * Can only be called by the proposed owner\n     */\n    function acceptOwner() external override {\n        if (msg.sender != _proposedNewOwner) revert CommonEventsAndErrors.InvalidAccess();\n\n        emit NewOwnerAccepted(owner, msg.sender);\n        owner = msg.sender;\n        delete _proposedNewOwner;\n    }\n\n    /**\n     * @notice Grant `allowedCaller` the rights to call the function selectors in the access list.\n     * @dev fnSelector == bytes4(keccak256(\"fn(argType1,argType2,...)\"))\n     */\n    function setExplicitAccess(address allowedCaller, ExplicitAccess[] calldata access) external override onlyElevatedAccess {\n        if (allowedCaller == address(0)) revert CommonEventsAndErrors.InvalidAddress(allowedCaller);\n        ExplicitAccess memory _access;\n        for (uint256 i; i < access.length; ++i) {\n            _access = access[i];\n            emit ExplicitAccessSet(allowedCaller, _access.fnSelector, _access.allowed);\n            explicitFunctionAccess[allowedCaller][_access.fnSelector] = _access.allowed;\n        }\n    }\n\n    function isElevatedAccess(address caller, bytes4 fnSelector) internal view returns (bool) {\n        return (\n            caller == owner || \n            explicitFunctionAccess[caller][fnSelector]\n        );\n    }\n\n    /**\n     * @notice The owner is allowed to call, or if explicit access has been given to the caller.\n     * @dev Important: Only for use when called from an *external* contract. \n     * If a function with this modifier is called internally then the `msg.sig` \n     * will still refer to the top level externally called function.\n     */\n    modifier onlyElevatedAccess() {\n        if (!isElevatedAccess(msg.sender, msg.sig)) revert CommonEventsAndErrors.InvalidAccess();\n        _;\n    }\n}\n"
      },
      "contracts/common/access/Whitelisted.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (common/access/Whitelisted.sol)\n\nimport { IWhitelisted } from \"contracts/interfaces/common/access/IWhitelisted.sol\";\nimport { OrigamiElevatedAccess } from \"contracts/common/access/OrigamiElevatedAccess.sol\";\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\n\n/**\n * @title Whitelisted abstract contract\n * @notice Functionality to deny non-EOA addresses unless whitelisted\n */\nabstract contract Whitelisted is IWhitelisted, OrigamiElevatedAccess {\n    /**\n     * @notice Allow all (both EOAs and contracts) without whitelisting\n     */\n    bool public override allowAll;\n\n    /**\n     * @notice A mapping of whitelisted accounts (not required for EOAs)\n     */\n    mapping(address account => bool allowed) public override allowedAccounts;\n\n    /**\n     * @notice Allow all callers without whitelisting\n     */\n    function setAllowAll(bool value) external override onlyElevatedAccess {\n        allowAll = value;\n        emit AllowAllSet(value);\n    }\n\n    /**\n     * @notice Set whether a given account is allowed or not\n     */\n    function setAllowAccount(address account, bool value) external override onlyElevatedAccess {\n        if (account == address(0)) revert CommonEventsAndErrors.InvalidAddress(account);\n        if (account.code.length == 0) revert CommonEventsAndErrors.InvalidAddress(account);\n\n        allowedAccounts[account] = value;\n        emit AllowAccountSet(account, value);\n    }\n\n    /**\n     * @notice Returns false for contracts unless whitelisted, or until allowAll is set to true.\n     * @dev This cannot block contracts which deposit within their constructor, but the goal is to minimise 3rd\n     * party integrations. This will also deny contract based wallets (eg Gnosis Safe)\n     */\n    function _isAllowed(address account) internal view returns (bool) {\n        if (allowAll) return true;\n\n        // Note: If the account is a contract and access is checked within it's constructor\n        // then this will still return true (unavoidable). This is just a deterrant for non-approved integrations, \n        // not intended as full protection.\n        if (account.code.length == 0) return true;\n\n        // Contracts need to be explicitly allowed\n        return allowedAccounts[account];\n    }\n}\n"
      },
      "contracts/interfaces/common/access/IOrigamiElevatedAccess.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/access/IOrigamiElevatedAccess.sol)\n\n/**\n * @notice Inherit to add Owner roles for DAO elevated access.\n */ \ninterface IOrigamiElevatedAccess {\n    event ExplicitAccessSet(address indexed account, bytes4 indexed fnSelector, bool indexed value);\n\n    event NewOwnerProposed(address indexed oldOwner, address indexed oldProposedOwner, address indexed newProposedOwner);\n    event NewOwnerAccepted(address indexed oldOwner, address indexed newOwner);\n\n    struct ExplicitAccess {\n        bytes4 fnSelector;\n        bool allowed;\n    }\n\n    /**\n     * @notice The address of the current owner.\n     */ \n    function owner() external returns (address);\n\n    /**\n     * @notice Explicit approval for an address to execute a function.\n     * allowedCaller => function selector => true/false\n     */\n    function explicitFunctionAccess(address contractAddr, bytes4 functionSelector) external returns (bool);\n\n    /**\n     * @notice Proposes a new Owner.\n     * Can only be called by the current owner\n     */\n    function proposeNewOwner(address account) external;\n\n    /**\n     * @notice Caller accepts the role as new Owner.\n     * Can only be called by the proposed owner\n     */\n    function acceptOwner() external;\n\n    /**\n     * @notice Grant `allowedCaller` the rights to call the function selectors in the access list.\n     * @dev fnSelector == bytes4(keccak256(\"fn(argType1,argType2,...)\"))\n     */\n    function setExplicitAccess(address allowedCaller, ExplicitAccess[] calldata access) external;\n}\n"
      },
      "contracts/interfaces/common/access/IWhitelisted.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/access/Whitelisted.sol)\n\n/**\n * @title Whitelisted abstract contract\n * @notice Functionality to deny non-EOA addresses unless whitelisted\n */\ninterface IWhitelisted {\n    event AllowAllSet(bool value);\n    event AllowAccountSet(address indexed account, bool value);\n\n    /**\n     * @notice Allow all (both EOAs and contracts) without whitelisting\n     */\n    function allowAll() external view returns (bool);\n\n    /**\n     * @notice A mapping of whitelisted accounts (not required for EOAs)\n     */\n    function allowedAccounts(address account) external view returns (bool allowed);\n\n    /**\n     * @notice Allow all callers without whitelisting\n     */\n    function setAllowAll(bool value) external;\n\n    /**\n     * @notice Set whether a given account is allowed or not\n     */\n    function setAllowAccount(address account, bool value) external;\n}\n"
      },
      "contracts/interfaces/common/borrowAndLend/IOrigamiBorrowAndLend.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/borrowAndLend/IOrigamiBorrowAndLend.sol)\n\n/**\n * @notice An Origami abstraction over a borrow/lend money market for\n * a single `supplyToken` and a single `borrowToken`, for a given `positionOwner`\n */\ninterface IOrigamiBorrowAndLend {\n    event PositionOwnerSet(address indexed account);\n    event SurplusDebtReclaimed(uint256 amount, address indexed recipient);\n\n    /**\n     * @notice Set the position owner who can borrow/lend via this contract\n     */\n    function setPositionOwner(address account) external;\n\n    /**\n     * @notice Supply tokens as collateral\n     */\n    function supply(\n        uint256 supplyAmount\n    ) external;\n\n    /**\n     * @notice Withdraw collateral tokens to recipient\n     * @dev Set `withdrawAmount` to type(uint256).max in order to withdraw the whole balance\n     */\n    function withdraw(\n        uint256 withdrawAmount, \n        address recipient\n    ) external returns (uint256 amountWithdrawn);\n\n    /**\n     * @notice Borrow tokens and send to recipient\n     */\n    function borrow(\n        uint256 borrowAmount,\n        address recipient\n    ) external;\n\n    /**\n     * @notice Repay debt. \n     * @dev If `repayAmount` is set higher than the actual outstanding debt balance, it will be capped\n     * to that outstanding debt balance\n     * `debtRepaidAmount` return parameter will be capped to the outstanding debt balance.\n     * Any surplus debtTokens (if debt fully repaid) will remain in this contract\n     */\n    function repay(\n        uint256 repayAmount\n    ) external returns (uint256 debtRepaidAmount);\n\n    /**\n     * @notice Repay debt and withdraw collateral in one step\n     * @dev If `repayAmount` is set higher than the actual outstanding debt balance, it will be capped\n     * to that outstanding debt balance\n     * Set `withdrawAmount` to type(uint256).max in order to withdraw the whole balance\n     * `debtRepaidAmount` return parameter will be capped to the outstanding debt amount.\n     * Any surplus debtTokens (if debt fully repaid) will remain in this contract\n     */\n    function repayAndWithdraw(\n        uint256 repayAmount, \n        uint256 withdrawAmount, \n        address recipient\n    ) external returns (\n        uint256 debtRepaidAmount,\n        uint256 withdrawnAmount\n    );\n\n    /**\n     * @notice Supply collateral and borrow in one step\n     */\n    function supplyAndBorrow(\n        uint256 supplyAmount, \n        uint256 borrowAmount, \n        address recipient\n    ) external;\n\n    /**\n     * @notice The approved owner of the borrow/lend position\n     */\n    function positionOwner() external view returns (address);\n\n    /**\n     * @notice The token supplied as collateral\n     */\n    function supplyToken() external view returns (address);\n\n    /**\n     * @notice The token which is borrowed\n     */\n    function borrowToken() external view returns (address);\n\n    /**\n     * @notice The current (manually tracked) balance of tokens supplied\n     */\n    function suppliedBalance() external view returns (uint256);\n\n    /**\n     * @notice The current debt balance of tokens borrowed\n     */\n    function debtBalance() external view returns (uint256);\n\n    /**\n     * @notice Whether a given Assets/Liabilities Ratio is safe, given the upstream\n     * money market parameters\n     */\n    function isSafeAlRatio(uint256 alRatio) external view returns (bool);\n\n    /**\n     * @notice How many `supplyToken` are available to withdraw from collateral\n     * from the entire protocol, assuming this contract has fully paid down its debt\n     */\n    function availableToWithdraw() external view returns (uint256);\n\n    /**\n     * @notice How much more capacity is available to supply\n     */\n    function availableToSupply() external view returns (\n        uint256 supplyCap,\n        uint256 available\n    );\n\n    /**\n     * @notice How many `borrowToken` are available to borrow\n     * from the entire protocol\n     */\n    function availableToBorrow() external view returns (uint256);\n}"
      },
      "contracts/interfaces/common/borrowAndLend/IOrigamiMorphoBorrowAndLend.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/borrowAndLend/IOrigamiMorphoBorrowAndLend.sol)\n\nimport { IOrigamiBorrowAndLend } from \"contracts/interfaces/common/borrowAndLend/IOrigamiBorrowAndLend.sol\";\nimport { IMorpho, Id as MorphoMarketId, MarketParams as MorphoMarketParams } from \"@morpho-org/morpho-blue/src/interfaces/IMorpho.sol\";\nimport { IOrigamiSwapper } from \"contracts/interfaces/common/swappers/IOrigamiSwapper.sol\";\n\n/**\n * @notice An Origami abstraction over a borrow/lend money market for\n * a single `supplyToken` and a single `borrowToken`.\n * This is a Morpho specific interface\n */\ninterface IOrigamiMorphoBorrowAndLend is IOrigamiBorrowAndLend {\n    event MaxSafeLtvSet(uint256 _maxSafeLtv);\n    event SwapperSet(address indexed swapper);\n\n    /**\n     * @notice Set the max LTV we will allow when borrowing or withdrawing collateral.\n     * @dev The morpho LTV is the liquidation LTV only, we don't want to allow up to that limit\n     */\n    function setMaxSafeLtv(uint256 _maxSafeLtv) external;\n\n    /**\n     * @notice Set the swapper responsible for `borrowToken` <--> `supplyToken` swaps\n     */\n    function setSwapper(address _swapper) external;\n\n    /**\n     * @notice Increase the leverage of the existing position, by supplying `supplyToken` as collateral\n     * and borrowing `borrowToken` and swapping that back to `supplyToken`\n     * @dev The totalCollateralSupplied may include any surplus after swapping from the debt to collateral\n     */\n    function increaseLeverage(\n        uint256 supplyCollateralAmount,\n        uint256 borrowAmount,\n        bytes memory swapData,\n        uint256 supplyCollateralSurplusThreshold\n    ) external returns (uint256 totalCollateralSupplied);\n\n    /**\n     * @notice Decrease the leverage of the existing position, by repaying `borrowToken`\n     * and withdrawing `supplyToken` collateral then swapping that back to `borrowToken`\n     */\n    function decreaseLeverage(\n        uint256 repayAmount,\n        uint256 withdrawCollateralAmount,\n        bytes memory swapData,\n        uint256 repaySurplusThreshold\n    ) external returns  (\n        uint256 debtRepaidAmount, \n        uint256 surplusDebtRepaid\n    );\n\n    /**\n     * @notice The morpho singleton contract\n     */\n    function morpho() external view returns (IMorpho);\n\n    /**\n     * @notice The Morpho oracle used for the target market\n     */\n    function morphoMarketOracle() external view returns (address);\n\n    /**\n     * @notice The Morpho Interest Rate Model used for the target market\n     */\n    function morphoMarketIrm() external view returns (address);\n\n    /**\n     * @notice The Morpho Liquidation LTV for the target market\n     */\n    function morphoMarketLltv() external view returns (uint96);\n\n    /**\n     * @notice The Morpho market parameters\n     */\n    function getMarketParams() external view returns (MorphoMarketParams memory);\n\n    /**\n     * @notice The derived Morpho market ID given the market parameters\n     */\n    function marketId() external view returns (MorphoMarketId);\n\n    /**\n     * @notice The max LTV we will allow when borrowing or withdrawing collateral.\n     * @dev The morpho LTV is the liquidation LTV only, we don't want to allow up to that limit\n     */\n    function maxSafeLtv() external view returns (uint256);\n    \n    /**\n     * @notice The swapper for `borrowToken` <--> `supplyToken`\n     */\n    function swapper() external view returns (IOrigamiSwapper);\n\n    /**\n     * @notice Returns the curent Morpho position data\n     */\n    function debtAccountData() external view returns (\n        uint256 collateral,\n        uint256 collateralPrice,\n        uint256 borrowed,\n        uint256 maxBorrow,\n        uint256 currentLtv,\n        uint256 healthFactor\n    );\n}"
      },
      "contracts/interfaces/common/oracle/IOrigamiOracle.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/oracle/IOrigamiOracle.sol)\n\nimport { OrigamiMath } from \"contracts/libraries/OrigamiMath.sol\";\n\n/**\n * @notice An oracle which returns prices for pairs of assets, where an asset\n * could refer to a token (eg DAI) or a currency (eg USD)\n * Convention is the same as the FX market. Given the DAI/USD pair:\n *   - DAI = Base Asset (LHS of pair)\n *   - USD = Quote Asset (RHS of pair)\n * This price defines how many USD you get if selling 1 DAI\n *\n * Further, an oracle can define two PriceType's:\n *   - SPOT_PRICE: The latest spot price, for example from a chainlink oracle\n *   - HISTORIC_PRICE: An expected (eg 1:1 peg) or calculated historic price (eg TWAP)\n *\n * For assets which do are not tokens (eg USD), an internal address reference will be used\n * since this is for internal purposes only\n */\ninterface IOrigamiOracle {\n    error InvalidPrice(address oracle, int256 price);\n    error InvalidOracleData(address oracle);\n    error StalePrice(address oracle, uint256 lastUpdatedAt, int256 price);\n    error UnknownPriceType(uint8 priceType);\n    error BelowMinValidRange(address oracle, uint256 price, uint128 floor);\n    error AboveMaxValidRange(address oracle, uint256 price, uint128 ceiling);\n\n    event ValidPriceRangeSet(uint128 validFloor, uint128 validCeiling);\n\n    enum PriceType {\n        /// @notice The current spot price of this Oracle\n        SPOT_PRICE,\n\n        /// @notice The historic price of this Oracle. \n        /// It may be a fixed expectation (eg DAI/USD would be fixed to 1)\n        /// or use a TWAP or some other moving average, etc.\n        HISTORIC_PRICE\n    }\n\n    /**\n     * @dev Wrapped in a struct to remove stack-too-deep constraints\n     */\n    struct BaseOracleParams {\n        string description;\n        address baseAssetAddress;\n        uint8 baseAssetDecimals;\n        address quoteAssetAddress;\n        uint8 quoteAssetDecimals;\n    }\n\n    /**\n     * @notice The address used to reference the baseAsset for amount conversions\n     */\n    function baseAsset() external view returns (address);\n\n    /**\n     * @notice The address used to reference the quoteAsset for amount conversions\n     */\n    function quoteAsset() external view returns (address);\n\n    /**\n     * @notice The number of decimals of precision the price is returned as\n     */\n    function decimals() external view returns (uint8);\n\n    /**\n     * @notice The precision that the cross rate oracle price is returned as: `10^decimals`\n     */\n    function precision() external view returns (uint256);\n\n    /**\n     * @notice A human readable description for this oracle\n     */\n    function description() external view returns (string memory);\n\n    /**\n     * @notice Return the latest oracle price, to `decimals` precision\n     * @dev This may still revert - eg if deemed stale, div by 0, negative price\n     * @param priceType What kind of price - Spot or Historic\n     * @param roundingMode Round the price at each intermediate step such that the final price rounds in the specified direction.\n     */\n    function latestPrice(\n        PriceType priceType, \n        OrigamiMath.Rounding roundingMode\n    ) external view returns (uint256 price);\n\n    /**\n     * @notice Same as `latestPrice()` but for two separate prices from this oracle\t\n     */\n    function latestPrices(\n        PriceType priceType1, \n        OrigamiMath.Rounding roundingMode1,\n        PriceType priceType2, \n        OrigamiMath.Rounding roundingMode2\n    ) external view returns (\n        uint256 price1, \n        uint256 price2, \n        address oracleBaseAsset,\n        address oracleQuoteAsset\n    );\n\n    /**\n     * @notice Convert either the baseAsset->quoteAsset or quoteAsset->baseAsset\n     * @dev The `fromAssetAmount` needs to be in it's natural fixed point precision (eg USDC=6dp)\n     * The `toAssetAmount` will also be returned in it's natural fixed point precision\n     */\n    function convertAmount(\n        address fromAsset,\n        uint256 fromAssetAmount,\n        PriceType priceType,\n        OrigamiMath.Rounding roundingMode\n    ) external view returns (uint256 toAssetAmount);\n\n    /**\n     * @notice Match whether a pair of assets match the base and quote asset on this oracle, in either order\n     */\n    function matchAssets(address asset1, address asset2) external view returns (bool);\n}\n"
      },
      "contracts/interfaces/common/swappers/IOrigamiSwapper.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/common/swappers/IOrigamiSwapper.sol)\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @notice An on chain swapper contract to integrate with the 1Inch router | 0x proxy, \n * possibly others which obtain quote calldata offchain and then execute via a low level call\n * to perform the swap onchain\n */\ninterface IOrigamiSwapper {\n    error UnknownSwapError(bytes result);\n    error InvalidSwap();\n\n    event Swap(address indexed sellToken, uint256 sellTokenAmount, address indexed buyToken, uint256 buyTokenAmount);\n\n    /**\n     * @notice Pull tokens from sender then execute the swap\n     */\n    function execute(\n        IERC20 sellToken, \n        uint256 sellTokenAmount, \n        IERC20 buyToken,\n        bytes memory swapData\n    ) external returns (uint256 buyTokenAmount);\n}\n"
      },
      "contracts/interfaces/investments/IOrigamiInvestment.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/IOrigamiInvestment.sol)\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\n\n/**\n * @title Origami Investment\n * @notice Users invest in the underlying protocol and receive a number of this Origami investment in return.\n * Origami will apply the accepted investment token into the underlying protocol in the most optimal way.\n */\ninterface IOrigamiInvestment is IERC20Metadata, IERC20Permit {\n    event TokenPricesSet(address indexed _tokenPrices);\n    event ManagerSet(address indexed manager);\n    event PerformanceFeeSet(uint256 fee);\n    \n    /**\n     * @notice Track the depoyed version of this contract. \n     */\n    function apiVersion() external pure returns (string memory);\n\n    /**\n     * @notice The underlying token this investment wraps. \n     * @dev For informational purposes only, eg integrations/FE\n     * If the investment wraps a protocol without an ERC20 (eg a non-liquid staked position)\n     * then this may be 0x0\n     */\n    function baseToken() external view returns (address);\n\n    /** \n     * @notice Emitted when a user makes a new investment\n     * @param user The user who made the investment\n     * @param fromTokenAmount The number of `fromToken` used to invest\n     * @param fromToken The token used to invest, one of `acceptedInvestTokens()`\n     * @param investmentAmount The number of investment tokens received, after fees\n     **/\n    event Invested(address indexed user, uint256 fromTokenAmount, address indexed fromToken, uint256 investmentAmount);\n\n    /**\n     * @notice Emitted when a user exists a position in an investment\n     * @param user The user who exited the investment\n     * @param investmentAmount The number of Origami investment tokens sold\n     * @param toToken The token the user exited into\n     * @param toTokenAmount The number of `toToken` received, after fees\n     * @param recipient The receipient address of the `toToken`s\n     **/\n    event Exited(address indexed user, uint256 investmentAmount, address indexed toToken, uint256 toTokenAmount, address indexed recipient);\n\n    /// @notice Errors for unsupported functions - for example if native chain ETH/AVAX/etc isn't a vaild investment\n    error Unsupported();\n\n    /**\n     * @notice The set of accepted tokens which can be used to invest.\n     * If the native chain ETH/AVAX is accepted, 0x0 will also be included in this list.\n     */\n    function acceptedInvestTokens() external view returns (address[] memory);\n\n    /**\n     * @notice The set of accepted tokens which can be used to exit into.\n     * If the native chain ETH/AVAX is accepted, 0x0 will also be included in this list.\n     */\n    function acceptedExitTokens() external view returns (address[] memory);\n\n    /**\n     * @notice Whether new investments are paused.\n     */\n    function areInvestmentsPaused() external view returns (bool);\n\n    /**\n     * @notice Whether exits are temporarily paused.\n     */\n    function areExitsPaused() external view returns (bool);\n\n    /**\n     * @notice Quote data required when entering into this investment.\n     */\n    struct InvestQuoteData {\n        /// @notice The token used to invest, which must be one of `acceptedInvestTokens()`\n        address fromToken;\n\n        /// @notice The quantity of `fromToken` to invest with\n        uint256 fromTokenAmount;\n\n        /// @notice The maximum acceptable slippage of the `expectedInvestmentAmount`\n        uint256 maxSlippageBps;\n\n        /// @notice The maximum deadline to execute the transaction.\n        uint256 deadline;\n\n        /// @notice The expected amount of this Origami Investment token to receive in return\n        uint256 expectedInvestmentAmount;\n\n        /// @notice The minimum amount of this Origami Investment Token to receive after\n        /// slippage has been applied.\n        uint256 minInvestmentAmount;\n\n        /// @notice Any extra quote parameters required by the underlying investment\n        bytes underlyingInvestmentQuoteData;\n    }\n\n    /**\n     * @notice Quote data required when exoomg this investment.\n     */\n    struct ExitQuoteData {\n        /// @notice The amount of this investment to sell\n        uint256 investmentTokenAmount;\n\n        /// @notice The token to sell into, which must be one of `acceptedExitTokens()`\n        address toToken;\n\n        /// @notice The maximum acceptable slippage of the `expectedToTokenAmount`\n        uint256 maxSlippageBps;\n\n        /// @notice The maximum deadline to execute the transaction.\n        uint256 deadline;\n\n        /// @notice The expected amount of `toToken` to receive in return\n        /// @dev Note slippage is applied to this when calling `invest()`\n        uint256 expectedToTokenAmount;\n\n        /// @notice The minimum amount of `toToken` to receive after\n        /// slippage has been applied.\n        uint256 minToTokenAmount;\n\n        /// @notice Any extra quote parameters required by the underlying investment\n        bytes underlyingInvestmentQuoteData;\n    }\n\n    /**\n     * @notice Get a quote to buy this Origami investment using one of the accepted tokens. \n     * @dev The 0x0 address can be used for native chain ETH/AVAX\n     * @param fromTokenAmount How much of `fromToken` to invest with\n     * @param fromToken What ERC20 token to purchase with. This must be one of `acceptedInvestTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received investment amount\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return investFeeBps Any fees expected when investing with the given token, either from Origami or from the underlying investment.\n     */\n    function investQuote(\n        uint256 fromTokenAmount, \n        address fromToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external view returns (\n        InvestQuoteData memory quoteData, \n        uint256[] memory investFeeBps\n    );\n\n    /** \n      * @notice User buys this Origami investment with an amount of one of the approved ERC20 tokens. \n      * @param quoteData The quote data received from investQuote()\n      * @return investmentAmount The actual number of this Origami investment tokens received.\n      */\n    function investWithToken(\n        InvestQuoteData calldata quoteData\n    ) external returns (\n        uint256 investmentAmount\n    );\n\n    /** \n      * @notice User buys this Origami investment with an amount of native chain token (ETH/AVAX)\n      * @param quoteData The quote data received from investQuote()\n      * @return investmentAmount The actual number of this Origami investment tokens received.\n      */\n    function investWithNative(\n        InvestQuoteData calldata quoteData\n    ) external payable returns (\n        uint256 investmentAmount\n    );\n\n    /**\n     * @notice Get a quote to sell this Origami investment to receive one of the accepted tokens.\n     * @dev The 0x0 address can be used for native chain ETH/AVAX\n     * @param investmentAmount The number of Origami investment tokens to sell\n     * @param toToken The token to receive when selling. This must be one of `acceptedExitTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received `toToken`\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return exitFeeBps Any fees expected when exiting the investment to the nominated token, either from Origami or from the underlying investment.\n     */\n    function exitQuote(\n        uint256 investmentAmount,\n        address toToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external view returns (\n        ExitQuoteData memory quoteData, \n        uint256[] memory exitFeeBps\n    );\n\n    /** \n      * @notice Sell this Origami investment to receive one of the accepted tokens.\n      * @param quoteData The quote data received from exitQuote()\n      * @param recipient The receiving address of the `toToken`\n      * @return toTokenAmount The number of `toToken` tokens received upon selling the Origami investment tokens.\n      */\n    function exitToToken(\n        ExitQuoteData calldata quoteData,\n        address recipient\n    ) external returns (\n        uint256 toTokenAmount\n    );\n\n    /** \n      * @notice Sell this Origami investment to native ETH/AVAX.\n      * @param quoteData The quote data received from exitQuote()\n      * @param recipient The receiving address of the native chain token.\n      * @return nativeAmount The number of native chain ETH/AVAX/etc tokens received upon selling the Origami investment tokens.\n      */\n    function exitToNative(\n        ExitQuoteData calldata quoteData, \n        address payable recipient\n    ) external returns (\n        uint256 nativeAmount\n    );\n\n    /**\n     * @notice The maximum amount of fromToken's that can be deposited\n     * taking any other underlying protocol constraints into consideration\n     */\n    function maxInvest(address fromToken) external view returns (uint256 amount);\n\n    /**\n     * @notice The maximum amount of tokens that can be exited into the toToken\n     * taking any other underlying protocol constraints into consideration\n     */\n    function maxExit(address toToken) external view returns (uint256 amount);\n}\n"
      },
      "contracts/interfaces/investments/IOrigamiOTokenManager.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/IOrigamiOTokenManager.sol)\n\nimport { IOrigamiInvestment } from \"contracts/interfaces/investments/IOrigamiInvestment.sol\";\nimport { IOrigamiManagerPausable } from \"contracts/interfaces/investments/util/IOrigamiManagerPausable.sol\";\nimport { DynamicFees } from \"contracts/libraries/DynamicFees.sol\";\n\n/**\n * @title Origami oToken Manager (no native ETH/AVAX/etc)\n * @notice The delegated logic to handle deposits/exits into an oToken, and allocating the deposit tokens\n * into the underlying protocol\n */\ninterface IOrigamiOTokenManager is IOrigamiManagerPausable {\n    event InKindFees(DynamicFees.FeeType feeType, uint256 feeBps, uint256 feeAmount);\n    \n    /**\n     * @notice The underlying token this investment wraps. \n     * @dev For informational purposes only, eg integrations/FE\n     */\n    function baseToken() external view returns (address);\n\n    /**\n     * @notice The set of accepted tokens which can be used to invest.\n     */\n    function acceptedInvestTokens() external view returns (address[] memory);\n\n    /**\n     * @notice The set of accepted tokens which can be used to exit into.\n     */\n    function acceptedExitTokens() external view returns (address[] memory);\n\n    /**\n     * @notice Whether new investments are paused.\n     */\n    function areInvestmentsPaused() external view returns (bool);\n\n    /**\n     * @notice Whether exits are temporarily paused.\n     */\n    function areExitsPaused() external view returns (bool);\n\n    /**\n     * @notice Get a quote to buy this oToken using one of the accepted tokens. \n     * @param fromTokenAmount How much of `fromToken` to invest with\n     * @param fromToken What ERC20 token to purchase with. This must be one of `acceptedInvestTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received investment amount\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return investFeeBps Any fees expected when investing with the given token, either from Origami or from the underlying investment.\n     */\n    function investQuote(\n        uint256 fromTokenAmount, \n        address fromToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external view returns (\n        IOrigamiInvestment.InvestQuoteData memory quoteData, \n        uint256[] memory investFeeBps\n    );\n\n    /** \n      * @notice User buys this Origami investment with an amount of one of the approved ERC20 tokens. \n      * @param account The account to deposit on behalf of\n      * @param quoteData The quote data received from investQuote()\n      * @return investmentAmount The actual number of this Origami investment tokens received.\n      */\n    function investWithToken(\n        address account,\n        IOrigamiInvestment.InvestQuoteData calldata quoteData\n    ) external returns (\n        uint256 investmentAmount\n    );\n\n    /**\n     * @notice Get a quote to sell this oToken to receive one of the accepted tokens.\n     * @param investmentAmount The number of oTokens to sell\n     * @param toToken The token to receive when selling. This must be one of `acceptedExitTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received `toToken`\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return exitFeeBps Any fees expected when exiting the investment to the nominated token, either from Origami or from the underlying protocol.\n     */\n    function exitQuote(\n        uint256 investmentAmount,\n        address toToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external view returns (\n        IOrigamiInvestment.ExitQuoteData memory quoteData, \n        uint256[] memory exitFeeBps\n    );\n\n    /** \n      * @notice Sell this oToken to receive one of the accepted tokens. \n      * @param account The account to exit on behalf of\n      * @param quoteData The quote data received from exitQuote()\n      * @param recipient The receiving address of the `toToken`\n      * @return toTokenAmount The number of `toToken` tokens received upon selling the oToken\n      * @return toBurnAmount The number of oToken to be burnt after exiting this position\n      */\n    function exitToToken(\n        address account,\n        IOrigamiInvestment.ExitQuoteData calldata quoteData,\n        address recipient\n    ) external returns (uint256 toTokenAmount, uint256 toBurnAmount);\n\n    /**\n     * @notice The maximum amount of fromToken's that can be deposited\n     * taking any other underlying protocol constraints into consideration\n     */\n    function maxInvest(address fromToken) external view returns (uint256 amount);\n\n    /**\n     * @notice The maximum amount of tokens that can be exited into the toToken\n     * taking any other underlying protocol constraints into consideration\n     */\n    function maxExit(address toToken) external view returns (uint256 amount);\n}\n"
      },
      "contracts/interfaces/investments/lovToken/IOrigamiLovToken.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/lovToken/IOrigamiLovToken.sol)\n\nimport { IOrigamiOTokenManager } from \"contracts/interfaces/investments/IOrigamiOTokenManager.sol\";\nimport { IOrigamiInvestment } from \"contracts/interfaces/investments/IOrigamiInvestment.sol\";\n\n/**\n * @title Origami lovToken\n * \n * @notice Users deposit with an accepted token and are minted lovTokens\n * Origami will rebalance to lever up on the underlying reserve token, targetting a\n * specific A/L (assets / liabilities) range\n *\n * @dev The logic on how to handle the specific deposits/exits for each lovToken is delegated\n * to a manager contract\n */\ninterface IOrigamiLovToken is IOrigamiInvestment {\n    event PerformanceFeesCollected(address indexed feeCollector, uint256 mintAmount);\n    event FeeCollectorSet(address indexed feeCollector);\n    event MaxTotalSupplySet(uint256 maxTotalSupply);\n\n    /**\n     * @notice The token used to track reserves for this investment\n     */\n    function reserveToken() external view returns (address);\n\n    /**\n     * @notice The Origami contract managing the deposits/exits and the application of\n     * the deposit tokens into the underlying protocol\n     */\n    function manager() external view returns (IOrigamiOTokenManager);\n\n    /**\n     * @notice Set the Origami lovToken Manager.\n     */\n    function setManager(address _manager) external;\n\n    /**\n     * @notice Set the vault performance fee\n     * @dev Represented in basis points\n     */\n    function setAnnualPerformanceFee(uint48 _annualPerformanceFeeBps) external;\n\n    /**\n     * @notice Set the max total supply allowed for investments into this lovToken\n     */\n    function setMaxTotalSupply(uint256 _maxTotalSupply) external;\n\n    /**\n     * @notice Set the Origami performance fee collector address\n     */\n    function setFeeCollector(address _feeCollector) external;\n    \n    /**\n     * @notice Set the helper to calculate current off-chain/subgraph integration\n     */\n    function setTokenPrices(address _tokenPrices) external;\n\n    /** \n     * @notice Collect the performance fees to the Origami Treasury\n     */\n    function collectPerformanceFees() external returns (uint256 amount);\n\n    /**\n     * @notice How many reserve tokens would one get given a number of lovToken shares\n     * @dev Implementations must use the Oracle 'SPOT_PRICE' to value any debt in terms of the reserve token\n     */\n    function sharesToReserves(uint256 shares) external view returns (uint256);\n\n    /**\n     * @notice How many lovToken shares would one get given a number of reserve tokens\n     * @dev Implementations must use the Oracle 'SPOT_PRICE' to value any debt in terms of the reserve token\n     */\n    function reservesToShares(uint256 reserves) external view returns (uint256);\n\n    /**\n     * @notice How many reserve tokens would one get given a single share, as of now\n     * @dev Implementations must use the Oracle 'HISTORIC_PRICE' to value any debt in terms of the reserve token\n     */\n    function reservesPerShare() external view returns (uint256);\n    \n    /**\n     * @notice The current amount of available reserves for redemptions\n     * @dev Implementations must use the Oracle 'SPOT_PRICE' to value any debt in terms of the reserve token\n     */\n    function totalReserves() external view returns (uint256);\n\n    /**\n     * @notice The maximum allowed supply of this token for user investments\n     * @dev The actual totalSupply() may be greater than `maxTotalSupply`\n     * in order to start organically shrinking supply or from performance fees\n     */\n    function maxTotalSupply() external view returns (uint256);\n\n    /**\n     * @notice Retrieve the current assets, liabilities and calculate the ratio\n     * @dev Implementations must use the Oracle 'SPOT_PRICE' to value any debt in terms of the reserve token\n     */\n    function assetsAndLiabilities() external view returns (\n        uint256 assets,\n        uint256 liabilities,\n        uint256 ratio\n    );\n\n    /**\n     * @notice The current effective exposure (EE) of this lovToken\n     * to `PRECISION` precision\n     * @dev = reserves / (reserves - liabilities)\n     * Implementations must use the Oracle 'SPOT_PRICE' to value any debt in terms of the reserve token\n     */\n    function effectiveExposure() external view returns (uint128);\n\n    /**\n     * @notice The valid lower and upper bounds of A/L allowed when users deposit/exit into lovToken\n     * @dev Transactions will revert if the resulting A/L is outside of this range\n     */\n    function userALRange() external view returns (uint128 floor, uint128 ceiling);\n\n    /**\n     * @notice The current deposit and exit fee based on market conditions.\n     * Fees are the equivalent of burning lovToken shares - benefit remaining vault users\n     * @dev represented in basis points\n     */\n    function getDynamicFeesBps() external view returns (uint256 depositFeeBps, uint256 exitFeeBps);\n\n    /**\n     * @notice The address used to collect the Origami performance fees.\n     */\n    function feeCollector() external view returns (address);\n\n    /**\n     * @notice The annual performance fee to Origami treasury\n     * Represented in basis points\n     */\n    function annualPerformanceFeeBps() external view returns (uint48);\n\n    /**\n     * @notice The last time the performance fee was collected\n     */\n    function lastPerformanceFeeTime() external view returns (uint48);\n\n    /**\n     * @notice The performance fee amount which would be collected as of now, \n     * based on the total supply\n     */\n    function accruedPerformanceFee() external view returns (uint256);\n}"
      },
      "contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenManager.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/lovToken/managers/IOrigamiLovTokenManager.sol)\n\nimport { IOrigamiOTokenManager } from \"contracts/interfaces/investments/IOrigamiOTokenManager.sol\";\nimport { IWhitelisted } from \"contracts/interfaces/common/access/IWhitelisted.sol\";\nimport { IOrigamiOracle } from \"contracts/interfaces/common/oracle/IOrigamiOracle.sol\";\nimport { IOrigamiLovToken } from \"contracts/interfaces/investments/lovToken/IOrigamiLovToken.sol\";\n\n/**\n * @title Origami lovToken Manager\n * @notice The delegated logic to handle deposits/exits, and borrow/repay (rebalances) into the underlying reserve token\n */\ninterface IOrigamiLovTokenManager is IOrigamiOTokenManager, IWhitelisted {\n    event FeeConfigSet(uint16 maxExitFeeBps, uint16 minExitFeeBps, uint24 feeLeverageFactor);\n\n    event UserALRangeSet(uint128 floor, uint128 ceiling);\n    event RebalanceALRangeSet(uint128 floor, uint128 ceiling);\n\n    event Rebalance(\n        /// @dev positive when Origami supplies the `reserveToken` as new collateral, negative when Origami withdraws collateral\n        /// Represented in the units of the `reserveToken` of this lovToken\n        int256 collateralChange,\n\n        /// @dev positive when Origami borrows new debt, negative when Origami repays debt\n        /// Represented in the units of the `debtToken` of this lovToken\n        int256 debtChange,\n\n        /// @dev The Assets/Liabilities ratio before the rebalance\n        uint256 alRatioBefore,\n\n        /// @dev The Assets/Liabilities ratio after the rebalance\n        uint256 alRatioAfter\n    );\n    \n    error ALTooLow(uint128 ratioBefore, uint128 ratioAfter, uint128 minRatio);\n    error ALTooHigh(uint128 ratioBefore, uint128 ratioAfter, uint128 maxRatio);\n    error NoAvailableReserves();\n\n    /**\n     * @notice Set the minimum fee (in basis points) of lovToken's for deposit and exit,\n     * and also the nominal leverage factor applied within the fee calculations\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    function setFeeConfig(uint16 _minDepositFeeBps, uint16 _minExitFeeBps, uint24 _feeLeverageFactor) external;\n\n    /**\n     * @notice Set the valid lower and upper bounds of A/L when users deposit/exit into lovToken\n     */\n    function setUserALRange(uint128 floor, uint128 ceiling) external;\n\n    /**\n     * @notice Set the valid range for when a rebalance is not required.\n     */\n    function setRebalanceALRange(uint128 floor, uint128 ceiling) external;\n\n    /**\n     * @notice lovToken contract - eg lovDSR\n     */\n    function lovToken() external view returns (IOrigamiLovToken);\n\n    /**\n     * @notice The min deposit/exit fee and feeLeverageFactor configuration\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    function getFeeConfig() external view returns (uint64 minDepositFeeBps, uint64 minExitFeeBps, uint64 feeLeverageFactor);\n\n    /**\n     * @notice The current deposit and exit fee based on market conditions.\n     * Fees are the equivalent of burning lovToken shares - benefit remaining vault users\n     * @dev represented in basis points\n     */\n    function getDynamicFeesBps() external view returns (uint256 depositFeeBps, uint256 exitFeeBps);\n\n    /**\n     * @notice The valid lower and upper bounds of A/L allowed when users deposit/exit into lovToken\n     * @dev Transactions will revert if the resulting A/L is outside of this range\n     */\n    function userALRange() external view returns (uint128 floor, uint128 ceiling);\n\n    /**\n     * @notice The valid range for when a rebalance is not required.\n     * When a rebalance occurs, the transaction will revert if the resulting A/L is outside of this range.\n     */\n    function rebalanceALRange() external view returns (uint128 floor, uint128 ceiling);\n\n    /**\n     * @notice The common precision used\n     */\n    function PRECISION() external view returns (uint256);\n    \n    /**\n     * @notice The reserveToken that the lovToken levers up on\n     */\n    function reserveToken() external view returns (address);\n\n    /**\n     * @notice The token which lovToken borrows to increase the A/L ratio\n     */\n    function debtToken() external view returns (address);\n    \n    /**\n     * @notice The total balance of reserve tokens this lovToken holds, and also if deployed as collateral\n     * in other platforms\n     */\n    function reservesBalance() external view returns (uint256); \n\n    /**\n     * @notice The debt of the lovToken from the borrower, converted into the reserveToken\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function liabilities(IOrigamiOracle.PriceType debtPriceType) external view returns (uint256);\n\n    /**\n     * @notice The current asset/liability (A/L) of this lovToken\n     * to `PRECISION` precision\n     * @dev = reserves / liabilities\n     */\n    function assetToLiabilityRatio() external view returns (uint128);\n\n    /**\n     * @notice Retrieve the current assets, liabilities and calculate the ratio\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function assetsAndLiabilities(IOrigamiOracle.PriceType debtPriceType) external view returns (\n        uint256 assets,\n        uint256 liabilities,\n        uint256 ratio\n    );\n\n    /**\n     * @notice The current effective exposure (EE) of this lovToken\n     * to `PRECISION` precision\n     * @dev = reserves / (reserves - liabilities)\n     * Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function effectiveExposure(IOrigamiOracle.PriceType debtPriceType) external view returns (uint128);\n\n    /**\n     * @notice The amount of reserves that users may redeem their lovTokens as of this block\n     * @dev = reserves - liabilities\n     * Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function userRedeemableReserves(IOrigamiOracle.PriceType debtPriceType) external view returns (uint256);\n\n    /**\n     * @notice How many reserve tokens would one get given a number of lovToken shares\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function sharesToReserves(uint256 shares, IOrigamiOracle.PriceType debtPriceType) external view returns (uint256);\n\n    /**\n     * @notice How many lovToken shares would one get given a number of reserve tokens\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function reservesToShares(uint256 reserves, IOrigamiOracle.PriceType debtPriceType) external view returns (uint256);\n}\n"
      },
      "contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenMorphoManager.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/lovToken/managers/IOrigamiLovTokenMorphoManager.sol)\n\nimport { IOrigamiOracle } from \"contracts/interfaces/common/oracle/IOrigamiOracle.sol\";\nimport { IOrigamiLovTokenManager } from \"contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenManager.sol\";\nimport { IOrigamiMorphoBorrowAndLend } from \"contracts/interfaces/common/borrowAndLend/IOrigamiMorphoBorrowAndLend.sol\";\n\n/**\n * @title Origami LovToken Manager, for use with Morpho markets\n * @notice The `reserveToken` is deposited by users and supplied into Morpho as collateral\n * Upon a rebalanceDown (to decrease the A/L), the position is levered up\n */\ninterface IOrigamiLovTokenMorphoManager is IOrigamiLovTokenManager {\n    event OraclesSet(address indexed debtTokenToReserveTokenOracle, address indexed dynamicFeePriceOracle);\n    event BorrowLendSet(address indexed addr);\n\n    /**\n     * @notice Set the `reserveToken` <--> `debtToken` oracle configuration \n     */\n    function setOracles(address _debtTokenToReserveTokenOracle, address _dynamicFeePriceOracle) external;\n\n    /**\n     * @notice Set the Origami Borrow/Lend position holder\n     */\n    function setBorrowLend(address _address) external;\n\n    struct RebalanceUpParams {\n        // The amount of `debtToken` to repay\n        uint256 repayAmount;\n\n        // The amount of `reserveToken` collateral to withdraw\n        uint256 withdrawCollateralAmount;\n\n        // The swap quote data to swap from `reserveToken` -> `debtToken`\n        bytes swapData;\n\n        // The min balance threshold for when surplus balance of `debtToken` is\n        // repaid to the Morpho position\n        uint256 repaySurplusThreshold;\n\n        // The minimum acceptable A/L, will revert if below this\n        uint128 minNewAL;\n\n        // The maximum acceptable A/L, will revert if above this\n        uint128 maxNewAL;\n    }\n\n    /**\n     * @notice Increase the A/L by reducing liabilities.\n     * Uses Morpho's callback mechanism to efficiently lever up\n     */\n    function rebalanceUp(RebalanceUpParams calldata params) external;\n\n    /**\n     * @notice Force a rebalanceUp ignoring A/L ceiling/floor\n     * @dev Separate function to above to have stricter control on who can force\n     */\n    function forceRebalanceUp(RebalanceUpParams calldata params) external;\n\n    struct RebalanceDownParams {\n        // The amount of `reserveToken` collateral to supply\n        uint256 supplyAmount;\n\n        // The amount of `debtToken` to borrow\n        uint256 borrowAmount;\n        \n        // The swap quote data to swap from `debtToken` -> `reserveToken`\n        bytes swapData;\n\n        // The min balance threshold for when surplus balance of `reserveToken` is added as\n        // collateral to the Morpho position\n        uint256 supplyCollateralSurplusThreshold;\n        \n        // The minimum acceptable A/L, will revert if below this\n        uint128 minNewAL;\n\n        // The maximum acceptable A/L, will revert if above this\n        uint128 maxNewAL;\n    }\n\n    /**\n     * @notice Decrease the A/L by increasing liabilities. \n     * Uses Morpho's callback mechanism to efficiently lever up\n     */\n    function rebalanceDown(RebalanceDownParams calldata params) external;\n\n    /**\n     * @notice Force a rebalanceDown ignoring A/L ceiling/floor\n     * @dev Separate function to above to have stricter control on who can force\n     */\n    function forceRebalanceDown(RebalanceDownParams calldata params) external;\n\n    /**\n     * @notice The contract responsible for borrow/lend via external markets\n     */\n    function borrowLend() external view returns (IOrigamiMorphoBorrowAndLend);\n\n    /**\n     * @notice The oracle to convert `debtToken` <--> `reserveToken`\n     */\n    function debtTokenToReserveTokenOracle() external view returns (IOrigamiOracle);\n\n    /**\n     * @notice The base asset used when retrieving the prices for dynamic fee calculations.\n     */\n    function dynamicFeeOracleBaseToken() external view returns (address);\n\n    /**\n     * @notice The oracle to use when observing prices which are used for the dynamic fee calculations\n     */\n    function dynamicFeePriceOracle() external view returns (IOrigamiOracle);\n}"
      },
      "contracts/interfaces/investments/util/IOrigamiManagerPausable.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (interfaces/investments/util/IOrigamiManagerPausable.sol)\n\n/**\n * @title A mixin to add pause/unpause for Origami manager contracts\n */\ninterface IOrigamiManagerPausable {\n    struct Paused {\n        bool investmentsPaused;\n        bool exitsPaused;\n    }\n\n    event PauserSet(address indexed account, bool canPause);\n    event PausedSet(Paused paused);\n\n    /// @notice A set of accounts which are allowed to pause deposits/withdrawals immediately\n    /// under emergency\n    function pausers(address) external view returns (bool);\n\n    /// @notice Pause/unpause deposits or withdrawals\n    /// @dev Can only be called by allowed pausers or governance.\n    function setPaused(Paused memory updatedPaused) external;\n\n    /// @notice Allow/Deny an account to pause/unpause deposits or withdrawals\n    function setPauser(address account, bool canPause) external;\n\n    /// @notice Check if given account can pause investments/exits\n    function isPauser(address account) external view returns (bool canPause);\n}\n"
      },
      "contracts/investments/lovToken/managers/OrigamiAbstractLovTokenManager.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (investments/lovToken/managers/OrigamiAbstractLovTokenManager.sol)\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { IOrigamiInvestment } from \"contracts/interfaces/investments/IOrigamiInvestment.sol\";\nimport { IOrigamiLovTokenManager } from \"contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenManager.sol\";\nimport { IOrigamiOracle } from \"contracts/interfaces/common/oracle/IOrigamiOracle.sol\";\nimport { IOrigamiLovToken } from \"contracts/interfaces/investments/lovToken/IOrigamiLovToken.sol\";\n\nimport { OrigamiElevatedAccess } from \"contracts/common/access/OrigamiElevatedAccess.sol\";\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\nimport { OrigamiManagerPausable } from \"contracts/investments/util/OrigamiManagerPausable.sol\";\nimport { Range } from \"contracts/libraries/Range.sol\";\nimport { Whitelisted } from \"contracts/common/access/Whitelisted.sol\";\nimport { OrigamiMath } from \"contracts/libraries/OrigamiMath.sol\";\nimport { DynamicFees } from \"contracts/libraries/DynamicFees.sol\";\n\n/**\n * @title Abstract Origami lovToken Manager\n * @notice The delegated logic to handle deposits/exits, and borrow/repay (rebalances) into the underlying reserve token\n * @dev The `reserveToken` must have <= 18 decimal places.\n */\nabstract contract OrigamiAbstractLovTokenManager is IOrigamiLovTokenManager, OrigamiElevatedAccess, OrigamiManagerPausable, Whitelisted {\n    using Range for Range.Data;\n    using OrigamiMath for uint256;\n\n    /**\n     * @notice lovToken contract - eg lovDSR\n     */\n    IOrigamiLovToken public immutable override lovToken;\n\n    /**\n     * @notice The minimum fee (in basis points) when users deposit into from the lovToken. \n     * The fee is applied on the lovToken shares -- which are not minted, benefiting remaining holders.\n     */\n    uint64 internal _minDepositFeeBps;\n\n    /**\n     * @notice The minimum fee (in basis points) when users exit out from the lovToken. \n     * The fee is applied on the lovToken shares which are being exited\n     * These lovToken shares are burned, benefiting remaining holders.\n     */\n    uint64 internal _minExitFeeBps;\n\n    /**\n     * @notice The nominal leverage factor applied to the difference between the\n     * oracle SPOT_PRICE vs the HISTORIC_PRICE. Used within the fee calculation.\n     * eg: depositFee = 15 * (HISTORIC_PRICE - SPOT_PRICE) [when spot < historic]\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    uint64 internal _feeLeverageFactor;\n\n    /**\n     * @notice The valid lower and upper bounds of A/L allowed when users deposit/exit into lovToken\n     * @dev Transactions will revert if the resulting A/L is outside of this range\n     */\n    Range.Data public override userALRange;\n\n    /**\n     * @notice The valid range for when a rebalance is not required.\n     * When a rebalance occurs, the transaction will revert if the resulting A/L is outside of this range.\n     */\n    Range.Data public override rebalanceALRange;\n\n    /**\n     * @notice The common precision used\n     */\n    uint256 public constant override PRECISION = 1e18;\n\n    /**\n     * @notice The maximum A/L ratio possible (eg if debt=0)\n     */\n    uint128 internal constant MAX_AL_RATIO = type(uint128).max;\n\n    /**\n     * @notice The maxmimum EE ratio possible (eg if liabilities >= reserves)\n     */\n    uint128 internal constant MAX_EFECTIVE_EXPOSURE = type(uint128).max;\n\n    /**\n     * @dev Max ERC20 token amount for supply/allowances/etc\n     */\n    uint256 internal constant MAX_TOKEN_AMOUNT = type(uint256).max;\n\n    enum AlValidationMode {\n        LOWER_THAN_BEFORE, \n        HIGHER_THAN_BEFORE\n    }\n\n    constructor(\n        address _initialOwner,\n        address _lovToken\n    ) OrigamiElevatedAccess(_initialOwner) {\n        lovToken = IOrigamiLovToken(_lovToken);\n    }\n\n    /**\n     * @notice Set the minimum fee (in basis points) of lovToken's for deposit and exit,\n     * and also the nominal leverage factor applied within the fee calculations\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    function setFeeConfig(\n        uint16 minDepositFeeBps, \n        uint16 minExitFeeBps, \n        uint24 feeLeverageFactor\n    ) external override onlyElevatedAccess {\n        if (minDepositFeeBps > OrigamiMath.BASIS_POINTS_DIVISOR) revert CommonEventsAndErrors.InvalidParam();\n        if (minExitFeeBps > OrigamiMath.BASIS_POINTS_DIVISOR) revert CommonEventsAndErrors.InvalidParam();\n        emit FeeConfigSet(minDepositFeeBps, minExitFeeBps, feeLeverageFactor);\n        _minDepositFeeBps = minDepositFeeBps;\n        _minExitFeeBps = minExitFeeBps;\n        _feeLeverageFactor = feeLeverageFactor;\n    }\n\n    /**\n     * @notice The min deposit/exit fee and feeLeverageFactor configuration\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    function getFeeConfig() external override view returns (uint64, uint64, uint64) {\n        return (_minDepositFeeBps, _minExitFeeBps, _feeLeverageFactor);\n    }\n\n    /**\n     * @notice Set the valid lower and upper bounds of A/L when users deposit/exit into lovToken\n     */\n    function setUserALRange(uint128 floor, uint128 ceiling) external override onlyElevatedAccess {\n        if (floor <= PRECISION) revert Range.InvalidRange(floor, ceiling);\n        emit UserALRangeSet(floor, ceiling);\n        userALRange.set(floor, ceiling);\n\n        // Any extra validation on AL depending on the strategy\n        _validateAlRange(userALRange);\n    }\n\n    /**\n     * @notice Set the valid range for when a rebalance is not required.\n     */\n    function setRebalanceALRange(uint128 floor, uint128 ceiling) external override onlyElevatedAccess {\n        if (floor <= PRECISION) revert Range.InvalidRange(floor, ceiling);\n        emit RebalanceALRangeSet(floor, ceiling);\n        rebalanceALRange.set(floor, ceiling);\n\n        // Any extra validation on AL depending on the strategy\n        _validateAlRange(rebalanceALRange);\n    }\n\n    /**\n     * @notice Recover any token - should not be able to recover tokens which are normally\n     * held in this contract\n     * @param token Token to recover\n     * @param to Recipient address\n     * @param amount Amount to recover\n     */\n    function recoverToken(address token, address to, uint256 amount) external virtual;\n\n    /** \n      * @notice Deposit into the reserve token on behalf of a user\n      * @param account The user account which is investing.\n      * @param quoteData The quote data to deposit into the reserve token\n      * @return investmentAmount The actual number of receipt tokens received, inclusive of any fees.\n      */\n    function investWithToken(\n        address account,\n        IOrigamiInvestment.InvestQuoteData calldata quoteData\n    ) external virtual override onlyLovToken returns (\n        uint256 investmentAmount\n    ) {\n        if (_paused.investmentsPaused) revert CommonEventsAndErrors.IsPaused();\n        if (!_isAllowed(account)) revert CommonEventsAndErrors.InvalidAccess();\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        // Note this also checks that the debtToken/reserveToken oracle prices are valid.\n        uint128 oldAL = _assetToLiabilityRatio(cache);\n\n        uint256 newReservesAmount = _depositIntoReserves(quoteData.fromToken, quoteData.fromTokenAmount);\n\n        // The number of shares is calculated based off this `newReservesAmount`\n        // However not all of these shares are minted and given to the user -- the deposit fee is removed\n        investmentAmount = _reservesToShares(cache, newReservesAmount);\n        uint256 feeAmount;\n        uint256 feeBps = _dynamicDepositFeeBps();\n        (investmentAmount, feeAmount) = investmentAmount.splitSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_DOWN);\n        emit InKindFees(DynamicFees.FeeType.DEPOSIT_FEE, feeBps, feeAmount);\n\n        // Verify the amount\n        if (investmentAmount == 0) revert CommonEventsAndErrors.ExpectedNonZero();\n        if (investmentAmount < quoteData.minInvestmentAmount) {\n            revert CommonEventsAndErrors.Slippage(quoteData.minInvestmentAmount, investmentAmount);\n        }\n\n        // A user deposit will raise the A/L (more reserves, but the same debt)\n        // This needs to be validated so it doesn't go above the ceiling\n        // Not required if there are not yet any liabilities (where A/L would be uint128.max)\n        if (cache.liabilities != 0) {\n            uint128 newAL = refreshCacheAL(cache, IOrigamiOracle.PriceType.SPOT_PRICE);\n            _validateALRatio(userALRange, oldAL, newAL, AlValidationMode.HIGHER_THAN_BEFORE);\n        }\n    }\n\n    /** \n      * @notice Exit from the reserve token on behalf of a user.\n      * param account The account to exit on behalf of\n      * @param quoteData The quote data received from exitQuote()\n      * @param recipient The receiving address of the exit token\n      * @return toTokenAmount The number of tokens received upon selling the lovToken\n      * @return toBurnAmount The number of lovTokens to be burnt after exiting this position\n      */\n    function exitToToken(\n        address /*account*/,\n        IOrigamiInvestment.ExitQuoteData calldata quoteData,\n        address recipient\n    ) external virtual override onlyLovToken returns (\n        uint256 toTokenAmount,\n        uint256 toBurnAmount\n    ) {\n        if (_paused.exitsPaused) revert CommonEventsAndErrors.IsPaused();\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        // Note this also checks that the debtToken/reserveToken oracle prices are valid.\n        uint128 oldAL = _assetToLiabilityRatio(cache);\n\n        // The entire amount of lovTokens will be burned\n        // But only the non-fee portion is redeemed to reserves and sent to the user\n        toBurnAmount = quoteData.investmentTokenAmount;\n        uint256 feeBps = _dynamicExitFeeBps();\n        (uint256 reservesAmount, uint256 feeAmount) = toBurnAmount.splitSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_DOWN);\n        emit InKindFees(DynamicFees.FeeType.EXIT_FEE, feeBps, feeAmount);\n\n        // Given the number of redeemable lovToken's calculate how many reserves this equates to\n        // at the current share price and the reserve supply prior to exiting\n        reservesAmount = _sharesToReserves(cache, reservesAmount);\n\n        // Now exit from the reserves and check slippage\n        toTokenAmount = _redeemFromReserves(reservesAmount, quoteData.toToken, recipient);\n        if (toTokenAmount < quoteData.minToTokenAmount) {\n            revert CommonEventsAndErrors.Slippage(quoteData.minToTokenAmount, toTokenAmount);\n        }\n\n        // A user exit will lower the A/L (less reserves, but the same debt)\n        // This needs to be validated so it doesn't go below the floor\n        // Not required if there are not yet any liabilities (where A/L would be uint128.max)\n        if (cache.liabilities != 0) {\n            uint128 newAL = refreshCacheAL(cache, IOrigamiOracle.PriceType.SPOT_PRICE);\n            _validateALRatio(userALRange, oldAL, newAL, AlValidationMode.LOWER_THAN_BEFORE);\n        }\n    }\n\n    /**\n     * @notice Get a quote to buy this Origami investment using one of the accepted tokens. \n     * @param fromTokenAmount How much of `fromToken` to invest with\n     * @param fromToken What ERC20 token to purchase with. This must be one of `acceptedInvestTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received investment amount\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return investFeeBps Any fees expected when investing with the given token, either from Origami or from the underlying investment.\n     */\n    function investQuote(\n        uint256 fromTokenAmount, \n        address fromToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external virtual override view returns (\n        IOrigamiInvestment.InvestQuoteData memory quoteData, \n        uint256[] memory investFeeBps\n    ) {\n        if (fromTokenAmount == 0) revert CommonEventsAndErrors.ExpectedNonZero();\n\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n        uint256 _newReservesAmount = _previewDepositIntoReserves(fromToken, fromTokenAmount);\n\n        // The number of shares is calculated based off this `_newReservesAmount`\n        // However not all of these shares are minted and given to the user -- the deposit fee is removed\n        uint256 _investmentAmount = _reservesToShares(cache, _newReservesAmount);\n        uint256 _depositFeeRate = _dynamicDepositFeeBps();\n        _investmentAmount = _investmentAmount.subtractBps(_depositFeeRate, OrigamiMath.Rounding.ROUND_DOWN);\n\n        quoteData.fromToken = fromToken;\n        quoteData.fromTokenAmount = fromTokenAmount;\n        quoteData.maxSlippageBps = maxSlippageBps;\n        quoteData.deadline = deadline;\n        quoteData.expectedInvestmentAmount = _investmentAmount;\n        quoteData.minInvestmentAmount = _investmentAmount.subtractBps(maxSlippageBps, OrigamiMath.Rounding.ROUND_UP);\n        // quoteData.underlyingInvestmentQuoteData remains as bytes(0)\n\n        investFeeBps = new uint256[](1);\n        investFeeBps[0] = _depositFeeRate;\n    }\n\n    /**\n     * @notice The maximum amount of fromToken's that can be deposited into the lovToken\n     * taking into consideration: \n     *    1/ The max reserves in possible until the A/L ceiling would be hit\n     *    2/ Any other constraints of the underlying implementation\n     */\n    function maxInvest(address fromToken) external override view returns (uint256 fromTokenAmount) {\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        // First get the underlying implementation's max allowed\n        fromTokenAmount = _maxDepositIntoReserves(fromToken);\n\n        // Use the minimum number of reserves from both the lovToken.maxTotalSupply and userAL.ceiling restrictions\n        uint256 _minRemainingCapacity = _reservesCapacityFromTotalSupply(cache);\n        uint256 _remainingCapacityForAlCeiling = _reservesCapacityFromAlCeiling(cache);\n\n        if (_remainingCapacityForAlCeiling < _minRemainingCapacity) {\n            _minRemainingCapacity = _remainingCapacityForAlCeiling;\n        }\n\n        // Convert to the fromToken. Use previewMint as this amount of fromToken's\n        // should return the exact shares when invested\n        if (_minRemainingCapacity < type(uint256).max) {\n            _minRemainingCapacity = _previewMintReserves(fromToken, _minRemainingCapacity);\n        }\n\n        // Finally, use this remaining capcity if it's less than the underlying implementation's max allowed of fromToken\n        if (_minRemainingCapacity < fromTokenAmount) {\n            fromTokenAmount = _minRemainingCapacity;\n        }\n    }\n\n    /**\n     * @notice Get a quote to sell this Origami investment to receive one of the accepted tokens.\n     * @param investmentAmount The number of Origami investment tokens to sell\n     * @param toToken The token to receive when selling. This must be one of `acceptedExitTokens`\n     * @param maxSlippageBps The maximum acceptable slippage of the received `toToken`\n     * @param deadline The maximum deadline to execute the exit.\n     * @return quoteData The quote data, including any params required for the underlying investment type.\n     * @return exitFeeBps Any fees expected when exiting the investment to the nominated token, either from Origami or from the underlying investment.\n     */\n    function exitQuote(\n        uint256 investmentAmount,\n        address toToken,\n        uint256 maxSlippageBps,\n        uint256 deadline\n    ) external virtual override view returns (\n        IOrigamiInvestment.ExitQuoteData memory quoteData, \n        uint256[] memory exitFeeBps\n    ) {\n        if (investmentAmount == 0) revert CommonEventsAndErrors.ExpectedNonZero();\n\n        // Exit fees are taken from the lovToken amount, so get the non-fee amount to actually exit\n        uint256 _exitFeeRate = _dynamicExitFeeBps();\n        uint256 toExitAmount = investmentAmount.subtractBps(_exitFeeRate, OrigamiMath.Rounding.ROUND_DOWN);\n\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        // Convert to the underlying toToken\n        toExitAmount = _previewRedeemFromReserves(\n            // Convert the non-fee lovToken amount to ERC-4626 reserves\n            _sharesToReserves(cache, toExitAmount),\n            toToken\n        );\n\n        quoteData.investmentTokenAmount = investmentAmount;\n        quoteData.toToken = toToken;\n        quoteData.maxSlippageBps = maxSlippageBps;\n        quoteData.deadline = deadline;\n        quoteData.expectedToTokenAmount = toExitAmount;\n        quoteData.minToTokenAmount = toExitAmount.subtractBps(maxSlippageBps, OrigamiMath.Rounding.ROUND_UP);\n        // quoteData.underlyingInvestmentQuoteData remains as bytes(0)\n\n        exitFeeBps = new uint256[](1);\n        exitFeeBps[0] = _exitFeeRate;\n    }\n\n    /**\n     * @notice The maximum amount of lovToken shares that can be exited into the `toToken`\n     * taking into consideration: \n     *    1/ The max reserves out possible until the A/L floor would be hit\n     *    2/ Any other constraints from the underyling implementation\n     */\n    function maxExit(address toToken) external override view returns (uint256 sharesAmount) {\n        // Calculate the max reserves which can be removed before the A/L floor is hit\n        // Round up for the minimum reserves\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        uint256 _minReserves = cache.liabilities.mulDiv(\n            userALRange.floor, \n            PRECISION, \n            OrigamiMath.Rounding.ROUND_UP\n        );\n\n        // Only check the underlying implementation if there's capacity to remove reserves\n        if (cache.assets > _minReserves) {\n            // Calculate the max number of lovToken shares which can be exited given the A/L \n            // floor on reserves\n            uint256 _amountFromAvailableCapacity;\n            unchecked {\n                _amountFromAvailableCapacity = cache.assets - _minReserves;\n            }\n\n            // Check the underlying implementation's max reserves that can be redeemed\n            uint256 _underlyingAmount = _maxRedeemFromReserves(toToken);\n\n            // Use the minimum of both the underlying implementation max and\n            // the capacity based on the A/L floor\n            if (_underlyingAmount < _amountFromAvailableCapacity) {\n                _amountFromAvailableCapacity = _underlyingAmount;\n            }\n\n            // Convert reserves to lovToken shares\n            sharesAmount = _reservesToShares(cache, _amountFromAvailableCapacity);\n\n            // Since exit fees are taken when exiting (so these reserves aren't actually redeemed),\n            // reverse out the fees\n            // Round down to be the inverse of when they're applied (and rounded up) when exiting\n            sharesAmount = sharesAmount.inverseSubtractBps(_dynamicExitFeeBps(), OrigamiMath.Rounding.ROUND_DOWN);\n\n            // Finally use the min of the derived amount and the lovToken total supply\n            if (sharesAmount > cache.totalSupply) {\n                sharesAmount = cache.totalSupply;\n            }\n        }\n    }\n\n    /**\n     * @notice The current deposit and exit fee based on market conditions.\n     * Fees are the equivalent of burning lovToken shares - benefit remaining vault users\n     * @dev represented in basis points\n     */\n    function getDynamicFeesBps() external view returns (uint256 depositFeeBps, uint256 exitFeeBps) {\n        depositFeeBps = _dynamicDepositFeeBps();\n        exitFeeBps = _dynamicExitFeeBps();\n    }\n\n    /**\n     * @notice Whether new investments are paused.\n     */\n    function areInvestmentsPaused() external override view returns (bool) {\n        return _paused.investmentsPaused;\n    }\n\n    /**\n     * @notice Whether exits are temporarily paused.\n     */\n    function areExitsPaused() external override view returns (bool) {\n        return _paused.exitsPaused;\n    }\n\n    /**\n     * @notice The reserveToken that the lovToken levers up on\n     */\n    function reserveToken() public virtual override view returns (address);\n\n    /**\n     * @notice The total balance of reserve tokens this lovToken holds, and also if deployed as collateral\n     * in other platforms\n     * @dev Explicitly tracked rather than via reserveToken.balanceOf() to avoid donation/inflation vectors.\n     */\n    function reservesBalance() public virtual override view returns (uint256);\n\n    /**\n     * @notice The debt of the lovToken from the borrower, converted into the reserveToken\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function liabilities(IOrigamiOracle.PriceType debtPriceType) public virtual override view returns (uint256);\n\n    /**\n     * @notice The current asset/liability (A/L) of this lovToken\n     * to `PRECISION` precision\n     * @dev = reserves / liabilities\n     */\n    function assetToLiabilityRatio() external override view returns (uint128) {\n        return _assetToLiabilityRatio(populateCache(IOrigamiOracle.PriceType.SPOT_PRICE));\n    }\n\n    /**\n     * @notice Retrieve the current assets, liabilities and calculate the ratio\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function assetsAndLiabilities(IOrigamiOracle.PriceType debtPriceType) external override view returns (\n        uint256 /*assets*/,\n        uint256 /*liabilities*/,\n        uint256 /*ratio*/\n    ) {\n        Cache memory cache = populateCache(debtPriceType);\n        return (\n            cache.assets,\n            cache.liabilities,\n            _assetToLiabilityRatio(cache)\n        );\n    }\n\n    /**\n     * @notice The current effective exposure (EE) of this lovToken\n     * to `PRECISION` precision\n     * @dev = reserves / (reserves - liabilities)\n     * Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function effectiveExposure(IOrigamiOracle.PriceType debtPriceType) external override view returns (uint128) {\n        Cache memory cache = populateCache(debtPriceType);\n        if (cache.assets > cache.liabilities) {\n            uint256 redeemableReserves;\n            unchecked {\n                redeemableReserves = cache.assets - cache.liabilities;\n            }\n\n            // Round up for EE calc\n            uint256 ee = cache.assets.mulDiv(PRECISION, redeemableReserves, OrigamiMath.Rounding.ROUND_UP);\n            if (ee < MAX_EFECTIVE_EXPOSURE) {\n                return uint128(ee);\n            }\n        }\n\n        return MAX_EFECTIVE_EXPOSURE;\n    }\n\n    /**\n     * @notice The amount of reserves that users may redeem their lovTokens as of this block\n     * @dev = reserves - liabilities\n     * Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function userRedeemableReserves(IOrigamiOracle.PriceType debtPriceType) external override view returns (uint256) {\n        return _userRedeemableReserves(populateCache(debtPriceType));\n    }\n\n    /**\n     * @notice How many reserve tokens would one get given a number of lovToken shares \n     * and the current lovToken totalSupply\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function sharesToReserves(uint256 shares, IOrigamiOracle.PriceType debtPriceType) external override view returns (uint256) {\n        return _sharesToReserves(populateCache(debtPriceType), shares);\n    }\n\n    /**\n     * @notice How many lovToken shares would one get given a number of reserve tokens\n     * and the current lovToken totalSupply\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function reservesToShares(uint256 reserves, IOrigamiOracle.PriceType debtPriceType) external override view returns (uint256) {\n        return _reservesToShares(populateCache(debtPriceType), reserves);\n    }\n\n    // An internal cache to save having to recalculate\n    struct Cache {\n        uint256 assets;\n        uint256 liabilities;\n        uint256 totalSupply;\n    }\n\n    function populateCache(IOrigamiOracle.PriceType debtPriceType) internal view returns (Cache memory cache) {\n        cache.assets = reservesBalance();\n        cache.liabilities = liabilities(debtPriceType);\n        cache.totalSupply = lovToken.totalSupply();\n    }\n\n    function refreshCacheAL(Cache memory cache, IOrigamiOracle.PriceType debtPriceType) internal view returns (uint128) {\n        cache.assets = reservesBalance();\n        cache.liabilities = liabilities(debtPriceType);\n        return _assetToLiabilityRatio(cache);\n    }\n\n    /**\n     * @notice The current deposit fee based on market conditions.\n     * Deposit fees are applied to the portion of lovToken shares the depositor \n     * would have received. Instead that fee portion isn't minted (benefiting remaining users)\n     * @dev represented in basis points\n     */\n    function _dynamicDepositFeeBps() internal virtual view returns (uint256);\n\n    /**\n     * @notice The current exit fee based on market conditions.\n     * Exit fees are applied to the lovToken shares the user is exiting. \n     * That portion is burned prior to being redeemed (benefiting remaining users)\n     * @dev represented in basis points\n     */\n    function _dynamicExitFeeBps() internal virtual view returns (uint256);\n\n    /**\n     * @dev Perform any extra validation on the A/L range\n     * By default, nothing extra validation is required, however a manager implementation\n     * may decide to perform extra. For example if borrowing from Aave/Spark, \n     * this can check that the A/L floor is within a tolerable range which won't get liquidated\n     * Since those parameters could be updated at a later date by Aave/Spark\n     */\n    function _validateAlRange(Range.Data storage range) internal virtual view {}\n\n    function _userRedeemableReserves(Cache memory cache) internal pure returns (uint256) {\n        unchecked {\n            return cache.assets > cache.liabilities\n                ? cache.assets - cache.liabilities\n                : 0;\n        }\n    }\n\n    function _assetToLiabilityRatio(Cache memory cache) internal pure returns (uint128) {\n        if (cache.liabilities != 0) {\n            // Round down for A/L calc\n            uint256 alr = cache.assets.mulDiv(PRECISION, cache.liabilities, OrigamiMath.Rounding.ROUND_DOWN);\n            if (alr < MAX_AL_RATIO) {\n                return uint128(alr);\n            }\n        }\n\n        return MAX_AL_RATIO;\n    }\n\n    function _sharesToReserves(Cache memory cache, uint256 shares) internal view returns (uint256) {\n        // If totalSupply is zero, then just return shares 1:1 scaled down to the reserveToken decimals\n        // If > 0 then the decimal conversion is handled already (numerator cancels out denominator)\n        // Round down for calculating reserves from shares\n        return cache.totalSupply == 0\n            ? shares.scaleDown(_reservesToSharesScalar(), OrigamiMath.Rounding.ROUND_DOWN)\n            : shares.mulDiv(_userRedeemableReserves(cache), cache.totalSupply, OrigamiMath.Rounding.ROUND_DOWN);\n    }\n\n    function _reservesToShares(Cache memory cache, uint256 reserves) private view returns (uint256) {\n        // If totalSupply is zero, then just return reserves 1:1 scaled up to the shares decimals\n        // If > 0 then the decimal conversion is handled already (numerator cancels out denominator)\n        if (cache.totalSupply == 0) {\n            return reserves.scaleUp(_reservesToSharesScalar());\n        }\n\n        // In the unlikely case that no available reserves for user withdrawals (100% of reserves are held back to repay debt),\n        // then revert\n        uint256 _redeemableReserves = _userRedeemableReserves(cache);\n        if (_redeemableReserves == 0) {\n            revert NoAvailableReserves();\n        }\n\n        // Round down for calculating shares from reserves\n        return reserves.mulDiv(cache.totalSupply, _redeemableReserves, OrigamiMath.Rounding.ROUND_DOWN);\n    }\n\n    /**\n      * @dev Calculate the asset scalar to convert from reserveToken --> 18 decimal places (`PRECISION`)\n      * The reserveToken cannot have more than the lovToken decimals (18dp)\n      */\n    function _reservesToSharesScalar() internal view returns (uint256) {\n        uint8 _reservesDecimals = IERC20Metadata(reserveToken()).decimals();\n        uint8 _sharesDecimals = IERC20Metadata(address(lovToken)).decimals();\n        if (_reservesDecimals > _sharesDecimals) revert CommonEventsAndErrors.InvalidToken(reserveToken());\n        return 10 ** (_sharesDecimals - _reservesDecimals);\n    }\n\n    /**\n     * @notice Deposit a number of `fromToken` into the `reserveToken`\n     */\n    function _depositIntoReserves(address fromToken, uint256 fromTokenAmount) internal virtual returns (uint256 newReservesAmount);\n\n    /**\n     * @notice Calculate the amount of `reserveToken` will be deposited given an amount of `fromToken`\n     */\n    function _previewDepositIntoReserves(address fromToken, uint256 fromTokenAmount) internal virtual view returns (uint256 newReservesAmount);\n\n    /**\n     * @notice Maximum amount of `fromToken` that can be deposited into the `reserveToken`\n     */\n    function _maxDepositIntoReserves(address fromToken) internal virtual view returns (uint256 fromTokenAmount);\n\n    /**\n     * @notice Calculate the number of `toToken` required in order to mint a given number of `reserveTokens`\n     */\n    function _previewMintReserves(address toToken, uint256 reservesAmount) internal virtual view returns (uint256 toTokenAmount);\n\n    /**\n     * @notice Redeem a number of `reserveToken` into `toToken`\n     */\n    function _redeemFromReserves(uint256 reservesAmount, address toToken, address recipient) internal virtual returns (uint256 toTokenAmount);\n\n    /**\n     * @notice Calculate the number of `toToken` recevied if redeeming a number of `reserveToken`\n     */\n    function _previewRedeemFromReserves(uint256 reservesAmount, address toToken) internal virtual view returns (uint256 toTokenAmount);\n\n    /**\n     * @notice Maximum amount of `reserveToken` that can be redeemed to `toToken`\n     */\n    function _maxRedeemFromReserves(address toToken) internal virtual view returns (uint256 reservesAmount);\n\n    /**\n     * @notice Validate that the A/L ratio hasn't moved beyond the given A/L range.\n     */\n    function _validateALRatio(Range.Data storage validRange, uint128 ratioBefore, uint128 ratioAfter, AlValidationMode alMode) internal virtual {\n        if (alMode == AlValidationMode.LOWER_THAN_BEFORE) {\n            // A/L needs to be decreasing (may be equal if a very small amount is deposited/exited)\n            if (ratioAfter > ratioBefore) revert ALTooHigh(ratioBefore, ratioAfter, ratioBefore);\n            \n            // Check that the new A/L is not below the floor\n            // In this mode, the A/L may be above the ceiling still, but should be decreasing\n            // Note: The A/L may not be strictly decreasing in this mode since the liabilities (in reserve terms) is also\n            // fluctuating\n            if (ratioAfter < validRange.floor) revert ALTooLow(ratioBefore, ratioAfter, validRange.floor);\n        } else {\n            // A/L needs to be increasing (may be equal if a very small amount is deposited/exited)\n            if (ratioAfter < ratioBefore) revert ALTooLow(ratioBefore, ratioAfter, ratioBefore);\n\n            // Check that the new A/L is not above the ceiling\n            // In this mode, the A/L may be below the floor still, but should be increasing\n            // Note: The A/L may not be strictly increasing in this mode since the liabilities (in reserve terms) is also\n            // fluctuating\n            if (ratioAfter > validRange.ceiling) revert ALTooHigh(ratioBefore, ratioAfter, validRange.ceiling);\n        }\n    }\n\n    /**\n     * @dev Recalculate the A/L and validate that it is still within the `rebalanceALRange`\n     */\n    function _validateAfterRebalance(\n        Cache memory cache, \n        uint128 alRatioBefore, \n        uint128 minNewAL, \n        uint128 maxNewAL,\n        AlValidationMode alValidationMode,\n        bool force\n    ) internal returns (uint128 alRatioAfter) {\n        // Need to recalculate both the assets and liabilities in the cache\n        alRatioAfter = refreshCacheAL(cache, IOrigamiOracle.PriceType.SPOT_PRICE);\n\n        // Ensure the A/L is within the expected slippage range\n        {\n            if (alRatioAfter < minNewAL) revert ALTooLow(alRatioBefore, alRatioAfter, minNewAL);\n            if (alRatioAfter > maxNewAL) revert ALTooHigh(alRatioBefore, alRatioAfter, maxNewAL);\n        }\n\n        if (!force)\n            _validateALRatio(rebalanceALRange, alRatioBefore, alRatioAfter, alValidationMode);\n    }\n\n    /**\n     * @dev Calculate the free capacity for new reserves, given the lovToken maxTotalSupply restriction\n     */\n    function _reservesCapacityFromTotalSupply(Cache memory cache) internal view returns (uint256) {\n        uint256 _maxTotalSupply = lovToken.maxTotalSupply();\n\n        if (_maxTotalSupply == type(uint256).max) {\n            return type(uint256).max;\n        }\n\n        // Number of lovToken shares available\n        uint256 _availableShares;\n        unchecked {\n            _availableShares = _maxTotalSupply > cache.totalSupply\n                ? _maxTotalSupply - cache.totalSupply\n                : 0;\n        }\n\n        // Take deposit fees into account\n        // Round down to be the inverse of when they're applied when depositing\n        _availableShares = _availableShares.inverseSubtractBps(_dynamicDepositFeeBps(), OrigamiMath.Rounding.ROUND_DOWN);\n\n        // Convert to reserve tokens\n        return _sharesToReserves(cache, _availableShares);\n    }\n\n    /**\n     * @dev Calculate the free capacity for new reserves, given the A/L ceiling restriction\n     */\n    function _reservesCapacityFromAlCeiling(Cache memory cache) internal view returns (uint256) {\n        if (cache.liabilities == 0) {\n            return type(uint256).max;\n        }\n\n        // This is ever so slightly conservative, as it calculates maxReserves which would result in\n        // an A/L strictly less than (<) the `userALRange.ceiling`, rather than exacly less-than-or-equal (<=)\n        // This is intentional to provide a slightly more conservative max amount which can be deposited.\n        // To get it exact, the userALRange.ceiling would need to be incremented by 1 (if not already type(uint128).max)\n        uint256 _maxReservesForAlCeiling = cache.liabilities.mulDiv(\n            userALRange.ceiling,\n            PRECISION, \n            OrigamiMath.Rounding.ROUND_DOWN\n        );\n\n        if (_maxReservesForAlCeiling > cache.assets) {\n            unchecked {\n                return _maxReservesForAlCeiling - cache.assets;\n            }\n        }\n\n        return 0;\n    }\n\n    modifier onlyLovToken() {\n        if (msg.sender != address(lovToken)) revert CommonEventsAndErrors.InvalidAccess();\n        _;\n    }\n}\n"
      },
      "contracts/investments/lovToken/managers/OrigamiLovTokenMorphoManager.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (investments/lovToken/managers/OrigamiLovTokenMorphoManager.sol)\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { IOrigamiLovTokenMorphoManager } from \"contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenMorphoManager.sol\";\nimport { IOrigamiOracle } from \"contracts/interfaces/common/oracle/IOrigamiOracle.sol\";\nimport { IOrigamiLovTokenManager } from \"contracts/interfaces/investments/lovToken/managers/IOrigamiLovTokenManager.sol\";\nimport { IOrigamiMorphoBorrowAndLend } from \"contracts/interfaces/common/borrowAndLend/IOrigamiMorphoBorrowAndLend.sol\";\n\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\nimport { OrigamiAbstractLovTokenManager } from \"contracts/investments/lovToken/managers/OrigamiAbstractLovTokenManager.sol\";\nimport { OrigamiMath } from \"contracts/libraries/OrigamiMath.sol\";\nimport { Range } from \"contracts/libraries/Range.sol\";\nimport { DynamicFees } from \"contracts/libraries/DynamicFees.sol\";\n\n/**\n * @title Origami LovToken Manager, for use with Morpho markets\n * @notice The `reserveToken` is deposited by users and supplied into Morpho as collateral\n * Upon a rebalanceDown (to decrease the A/L), the position is levered up\n */\ncontract OrigamiLovTokenMorphoManager is IOrigamiLovTokenMorphoManager, OrigamiAbstractLovTokenManager {\n    using SafeERC20 for IERC20;\n    using OrigamiMath for uint256;\n\n    /**\n     * @notice reserveToken that this lovToken levers up on\n     * This is also the asset which users deposit/exit with in this lovToken manager\n     */\n    IERC20 private immutable _reserveToken;\n\n    /**\n     * @notice The asset which lovToken borrows from the money market to increase the A/L ratio\n     */\n    IERC20 private immutable _debtToken;\n\n    /**\n     * @notice The base asset used when retrieving the prices for dynamic fee calculations.\n     */\n    address public immutable override dynamicFeeOracleBaseToken;\n\n    /**\n     * @notice The contract responsible for borrow/lend via external markets\n     */\n    IOrigamiMorphoBorrowAndLend public override borrowLend;\n\n    /**\n     * @notice The oracle to convert `debtToken` <--> `reserveToken`\n     */\n    IOrigamiOracle public override debtTokenToReserveTokenOracle;\n\n    /**\n     * @notice The oracle to use when observing prices which are used for the dynamic fee calculations\n     */\n    IOrigamiOracle public override dynamicFeePriceOracle;\n\n    /**\n     * @dev Internal struct used to abi.encode params through a flashloan request\n     */\n    enum RebalanceCallbackType {\n        REBALANCE_DOWN,\n        REBALANCE_UP\n    }\n\n    constructor(\n        address _initialOwner,\n        address _reserveToken_,\n        address _debtToken_,\n        address _dynamicFeeOracleBaseToken,\n        address _lovToken,\n        address _borrowLend\n    ) OrigamiAbstractLovTokenManager(_initialOwner, _lovToken) {\n        _reserveToken = IERC20(_reserveToken_);\n        _debtToken = IERC20(_debtToken_);\n        dynamicFeeOracleBaseToken = _dynamicFeeOracleBaseToken;\n        borrowLend = IOrigamiMorphoBorrowAndLend(_borrowLend);\n\n        // Validate the decimals of the reserve token\n        // A borrow token of non-18dp has been tested and is ok\n        // A reserve token of non-18dp has not been tested as yet.\n        {\n            uint256 _decimals = IERC20Metadata(_lovToken).decimals();\n            if (IERC20Metadata(_reserveToken_).decimals() != _decimals) revert CommonEventsAndErrors.InvalidToken(_reserveToken_);\n        }\n    }\n\n    /**\n     * @notice Set the `debtToken` <--> `reserveToken` oracle configuration \n     */\n    function setOracles(address _debtTokenToReserveTokenOracle, address _dynamicFeePriceOracle) external override onlyElevatedAccess {\n        debtTokenToReserveTokenOracle = _validatedOracle(_debtTokenToReserveTokenOracle, address(_reserveToken), address(_debtToken));\n        dynamicFeePriceOracle = _validatedOracle(_dynamicFeePriceOracle, dynamicFeeOracleBaseToken, address(_debtToken));\n        emit OraclesSet(_debtTokenToReserveTokenOracle, _dynamicFeePriceOracle);\n    }\n\n    /**\n     * @notice Set the Origami Borrow/Lend position holder\n     */\n    function setBorrowLend(address _address) external override onlyElevatedAccess {\n        if (_address == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0));\n        borrowLend = IOrigamiMorphoBorrowAndLend(_address);\n        emit BorrowLendSet(_address);\n    }\n\n    /**\n     * @notice Increase the A/L by reducing liabilities. Flash loan and repay debt, and withdraw collateral to repay the flash loan\n     */\n    function rebalanceUp(RebalanceUpParams calldata params) external override onlyElevatedAccess {\n        _rebalanceUp(params, false);\n    }\n\n    /**\n     * @notice Force a rebalanceUp ignoring A/L ceiling/floor\n     * @dev Separate function to above to have stricter control on who can force\n     */\n    function forceRebalanceUp(RebalanceUpParams calldata params) external override onlyElevatedAccess {\n        _rebalanceUp(params, true);\n    }\n\n    /**\n     * @notice Decrease the A/L by increasing liabilities. Flash loan `debtToken` swap to `reserveToken`\n     * and add as collateral into a money market. Then borrow `debtToken` to repay the flash loan.\n     */\n    function rebalanceDown(RebalanceDownParams calldata params) external override onlyElevatedAccess {\n        _rebalanceDown(params, false);\n    }\n    \n    /**\n     * @notice Force a rebalanceDown ignoring A/L ceiling/floor\n     * @dev Separate function to above to have stricter control on who can force\n     */\n    function forceRebalanceDown(RebalanceDownParams calldata params) external override onlyElevatedAccess {\n        _rebalanceDown(params, true);\n    }\n\n    function _rebalanceDown(RebalanceDownParams calldata params, bool force) internal {\n        // Get the current A/L to check for oracle prices, and so we can compare that the new A/L is lower after the rebalance\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n        uint128 alRatioBefore = _assetToLiabilityRatio(cache);\n\n        uint256 _totalCollateralSupplied = borrowLend.increaseLeverage(\n            params.supplyAmount,\n            params.borrowAmount,\n            params.swapData,\n            params.supplyCollateralSurplusThreshold\n        );\n\n        // Validate that the new A/L is still within the `rebalanceALRange` and expected slippage range\n        uint128 alRatioAfter = _validateAfterRebalance(\n            cache, \n            alRatioBefore, \n            params.minNewAL, \n            params.maxNewAL, \n            AlValidationMode.LOWER_THAN_BEFORE, \n            force\n        );\n\n        emit Rebalance(\n            int256(_totalCollateralSupplied),\n            int256(params.borrowAmount),\n            alRatioBefore,\n            alRatioAfter\n        );\n    }\n\n    function _rebalanceUp(RebalanceUpParams calldata params, bool force) internal {\n        // Get the current A/L to check for oracle prices, and so we can compare that the new A/L is lower after the rebalance\n        Cache memory cache = populateCache(IOrigamiOracle.PriceType.SPOT_PRICE);\n        uint128 alRatioBefore = _assetToLiabilityRatio(cache);\n\n        (uint256 _debtRepaidAmount, uint256 _surplusRepaidAmount) = borrowLend.decreaseLeverage(\n            params.repayAmount,\n            params.withdrawCollateralAmount,\n            params.swapData,\n            params.repaySurplusThreshold\n        );\n\n        // Repaying less than what was asked is only allowed in force mode.\n        // This will only happen when there is no more debt in the money market, ie we are fully delevered\n        if (_debtRepaidAmount != params.repayAmount) {\n            if (!force) revert CommonEventsAndErrors.InvalidAmount(address(_debtToken), params.repayAmount);\n        }\n\n        // Validate that the new A/L is still within the `rebalanceALRange` and expected slippage range\n        uint128 alRatioAfter = _validateAfterRebalance(\n            cache, \n            alRatioBefore, \n            params.minNewAL, \n            params.maxNewAL, \n            AlValidationMode.HIGHER_THAN_BEFORE, \n            force\n        );\n\n        emit Rebalance(\n            -int256(params.withdrawCollateralAmount),\n            -int256(_debtRepaidAmount + _surplusRepaidAmount),\n            alRatioBefore,\n            alRatioAfter\n        );\n    }\n\n    /**\n     * @notice Recover accidental donations.\n     * @param token Token to recover\n     * @param to Recipient address\n     * @param amount Amount to recover\n     */\n    function recoverToken(address token, address to, uint256 amount) external override onlyElevatedAccess {\n        emit CommonEventsAndErrors.TokenRecovered(to, token, amount);\n        IERC20(token).safeTransfer(to, amount);\n    }\n\n    /**\n     * @notice The total balance of reserve tokens this lovToken holds.\n     */\n    function reservesBalance() public override(OrigamiAbstractLovTokenManager,IOrigamiLovTokenManager) view returns (uint256) {\n        return borrowLend.suppliedBalance();\n    }\n\n    /**\n     * @notice The underlying token this investment wraps. In this case, it's the `reserveToken`\n     */\n    function baseToken() external override view returns (address) {\n        return address(_reserveToken);\n    }\n\n    /**\n     * @notice The set of accepted tokens which can be used to invest. \n     * Only the `reserveToken` in this instance\n     */\n    function acceptedInvestTokens() external override view returns (address[] memory tokens) {\n        tokens = new address[](1);\n        tokens[0] = address(_reserveToken);\n    }\n\n    /**\n     * @notice The set of accepted tokens which can be used to exit into.\n     * Only the `reserveToken` in this instance\n     */\n    function acceptedExitTokens() external override view returns (address[] memory tokens) {\n        tokens = new address[](1);\n        tokens[0] = address(_reserveToken);\n    }\n\n    /**\n     * @notice The reserveToken that the lovToken levers up on\n     */\n    function reserveToken() public override(OrigamiAbstractLovTokenManager,IOrigamiLovTokenManager) view returns (address) {\n        return address(_reserveToken);\n    }\n\n    /**\n     * @notice The asset which lovToken borrows to increase the A/L ratio\n     */\n    function debtToken() external override view returns (address) {\n        return address(_debtToken);\n    }\n\n    /**\n     * @notice The debt of the lovToken to the money market, converted into the `reserveToken`\n     * @dev Use the Oracle `debtPriceType` to value any debt in terms of the reserve token\n     */\n    function liabilities(IOrigamiOracle.PriceType debtPriceType) public override(OrigamiAbstractLovTokenManager,IOrigamiLovTokenManager) view returns (uint256) {\n        // In [debtToken] terms.\n        uint256 debt = borrowLend.debtBalance();\n        if (debt == 0) return 0;\n\n        // Convert the [debtToken] into the [reserveToken] terms\n        return debtTokenToReserveTokenOracle.convertAmount(\n            address(_debtToken),\n            debt,\n            debtPriceType, \n            OrigamiMath.Rounding.ROUND_UP\n        );\n    }\n\n    /**\n     * @notice The current deposit fee based on market conditions.\n     * Deposit fees are applied to the portion of lovToken shares the depositor \n     * would have received. Instead that fee portion isn't minted (benefiting remaining users)\n     * @dev represented in basis points\n     */\n    function _dynamicDepositFeeBps() internal override view returns (uint256) {\n        return DynamicFees.dynamicFeeBps(\n            DynamicFees.FeeType.DEPOSIT_FEE,\n            dynamicFeePriceOracle,\n            dynamicFeeOracleBaseToken,\n            _minDepositFeeBps,\n            _feeLeverageFactor\n        );\n    }\n\n    /**\n     * @notice The current exit fee based on market conditions.\n     * Exit fees are applied to the lovToken shares the user is exiting. \n     * That portion is burned prior to being redeemed (benefiting remaining users)\n     * @dev represented in basis points\n     */\n    function _dynamicExitFeeBps() internal override view returns (uint256) {\n        return DynamicFees.dynamicFeeBps(\n            DynamicFees.FeeType.EXIT_FEE,\n            dynamicFeePriceOracle,\n            dynamicFeeOracleBaseToken,\n            _minExitFeeBps,\n            _feeLeverageFactor\n        );\n    }\n\n    /**\n     * @notice Deposit a number of `fromToken` into the `reserveToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _depositIntoReserves(address fromToken, uint256 fromTokenAmount) internal override returns (uint256 newReservesAmount) {\n        if (fromToken == address(_reserveToken)) {\n            newReservesAmount = fromTokenAmount;\n\n            // Supply into the money market\n            IOrigamiMorphoBorrowAndLend _borrowLend = borrowLend;\n            _reserveToken.safeTransfer(address(_borrowLend), fromTokenAmount);\n            _borrowLend.supply(fromTokenAmount);\n        } else {\n            revert CommonEventsAndErrors.InvalidToken(fromToken);\n        }\n    }\n\n    /**\n     * @notice Calculate the amount of `reserveToken` will be deposited given an amount of `fromToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _previewDepositIntoReserves(address fromToken, uint256 fromTokenAmount) internal override view returns (uint256 newReservesAmount) {\n        return fromToken == address(_reserveToken) ? fromTokenAmount : 0;\n    }\n    \n    /**\n     * @notice Maximum amount of `fromToken` that can be deposited into the `reserveToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _maxDepositIntoReserves(address fromToken) internal override view returns (uint256 fromTokenAmount) {\n        if (fromToken == address(_reserveToken)) {\n            (uint256 _supplyCap, uint256 _available) = borrowLend.availableToSupply();\n            return _supplyCap == 0 ? MAX_TOKEN_AMOUNT : _available;\n        }\n\n        // Anything else returns 0\n    }\n\n    /**\n     * @notice Calculate the number of `toToken` required in order to mint a given number of `reserveToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _previewMintReserves(address toToken, uint256 reservesAmount) internal override view returns (uint256 newReservesAmount) {\n        return toToken == address(_reserveToken) ? reservesAmount : 0;\n    }\n\n    /**\n     * @notice Redeem a number of `reserveToken` into `toToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _redeemFromReserves(uint256 reservesAmount, address toToken, address recipient) internal override returns (uint256 toTokenAmount) {\n        if (toToken == address(_reserveToken)) {\n            toTokenAmount = reservesAmount;\n            uint256 _amountWithdrawn = borrowLend.withdraw(reservesAmount, recipient);\n            if (_amountWithdrawn != reservesAmount) revert CommonEventsAndErrors.InvalidAmount(toToken, reservesAmount);\n        } else {\n            revert CommonEventsAndErrors.InvalidToken(toToken);\n        }\n    }\n\n    /**\n     * @notice Calculate the number of `toToken` recevied if redeeming a number of `reserveToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _previewRedeemFromReserves(uint256 reservesAmount, address toToken) internal override view returns (uint256 toTokenAmount) {\n        return toToken == address(_reserveToken) ? reservesAmount : 0;\n    }\n\n    /**\n     * @notice Maximum amount of `reserveToken` that can be redeemed to `toToken`\n     * This vault only accepts where `fromToken` == `reserveToken`\n     */\n    function _maxRedeemFromReserves(address toToken) internal override view returns (uint256 reservesAmount) {\n        if (toToken == address(_reserveToken)) {\n            // Within Morpho, we can always withdraw our supplied collateral as it is siloed.\n            reservesAmount = borrowLend.suppliedBalance();\n        }\n\n        // Anything else returns 0\n    }\n\n    /**\n     * @dev Revert if the range is invalid comparing to upstrea Aave/Spark\n     */\n    function _validateAlRange(Range.Data storage range) internal override view {\n        if (!borrowLend.isSafeAlRatio(range.floor)) revert Range.InvalidRange(range.floor, range.ceiling);\n    }\n\n    function _validatedOracle(\n        address oracleAddress, \n        address baseAsset, \n        address quoteAsset\n    ) private view returns (IOrigamiOracle oracle) {\n        if (oracleAddress == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0));\n        oracle = IOrigamiOracle(oracleAddress);\n\n        // Validate the assets on the oracle match what this lovToken needs\n        if (!oracle.matchAssets(baseAsset, quoteAsset)) {\n            revert CommonEventsAndErrors.InvalidParam();\n        }\n    }\n}\n"
      },
      "contracts/investments/util/OrigamiManagerPausable.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (investments/util/OrigamiManagerPausable.sol)\n\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\nimport { OrigamiElevatedAccess } from \"contracts/common/access/OrigamiElevatedAccess.sol\";\nimport { IOrigamiManagerPausable } from \"contracts/interfaces/investments/util/IOrigamiManagerPausable.sol\";\n\n/**\n * @title A mixin to add pause/unpause for Origami manager contracts\n */\nabstract contract OrigamiManagerPausable is IOrigamiManagerPausable, OrigamiElevatedAccess {\n    /**\n     * @notice A set of accounts which are allowed to pause deposits/withdrawals immediately\n     * under emergency\n     */\n    mapping(address account => bool canPause) public pausers;\n\n    /**\n     * @notice The current paused/unpaused state of deposits/exits.\n     */\n    Paused internal _paused;\n\n    /**\n     * @notice Pause/unpause deposits or exits\n     * @dev Can only be called by allowed pausers.\n     */\n    function setPaused(Paused calldata updatedPaused) external {\n        if (!pausers[msg.sender]) revert CommonEventsAndErrors.InvalidAccess();\n        emit PausedSet(updatedPaused);\n        _paused = updatedPaused;\n    }\n\n    /**\n     * @notice Allow/Deny an account to pause/unpause deposits or exits\n     */\n    function setPauser(address account, bool canPause) external onlyElevatedAccess {\n        pausers[account] = canPause;\n        emit PauserSet(account, canPause);\n    }\n\n    /**\n     * @notice Check if given account can pause deposits/exits\n     */\n    function isPauser(address account) external view override returns (bool canPause) {\n        canPause = pausers[account];\n    }\n}\n"
      },
      "contracts/libraries/CommonEventsAndErrors.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (libraries/CommonEventsAndErrors.sol)\n\n/// @notice A collection of common events and errors thrown within the Origami contracts\nlibrary CommonEventsAndErrors {\n    error InsufficientBalance(address token, uint256 required, uint256 balance);\n    error InvalidToken(address token);\n    error InvalidParam();\n    error InvalidAddress(address addr);\n    error InvalidAmount(address token, uint256 amount);\n    error ExpectedNonZero();\n    error Slippage(uint256 minAmountExpected, uint256 actualAmount);\n    error IsPaused();\n    error UnknownExecuteError(bytes returndata);\n    error InvalidAccess();\n    error BreachedMaxTotalSupply(uint256 totalSupply, uint256 maxTotalSupply);\n\n    event TokenRecovered(address indexed to, address indexed token, uint256 amount);\n}\n"
      },
      "contracts/libraries/DynamicFees.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (libraries/DynamicFees.sol)\n\nimport { IOrigamiOracle } from \"contracts/interfaces/common/oracle/IOrigamiOracle.sol\";\nimport { OrigamiMath } from \"contracts/libraries/OrigamiMath.sol\";\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\n\n/**\n * @notice A helper to calculate dynamic entry and exit fees based off the difference\n * between an oracle historic vs spot price\n */\nlibrary DynamicFees {\n    using OrigamiMath for uint256;\n\n    enum FeeType {\n        DEPOSIT_FEE,\n        EXIT_FEE\n    }\n\n    /**\n     * @notice The current deposit or exit fee based on market conditions.\n     * Fees are applied to the portion of lovToken shares the depositor \n     * would have received. Instead that fee portion isn't minted (benefiting remaining users)\n     * Ignoring the minFeeBps, deposit vs exit fees are symmetric:\n     *   - A 0.004 cent increase in price (away from expected historic) should result a deposit fee of X bps\n     *   - A 0.004 cent decrease in price (away from expected historic) should result an exit fee, also of X bps\n     * ie X is the same in both cases.\n     * @dev feeLeverageFactor has 4dp precision\n     */\n    function dynamicFeeBps(\n        FeeType feeType,\n        IOrigamiOracle oracle,\n        address expectedBaseAsset,\n        uint64 minFeeBps,\n        uint256 feeLeverageFactor\n    ) internal view returns (uint256) {\n        // Pull the spot and expected historic price from the oracle.\n        // Round up for both to be consistent no matter if the oracle is in expected quoted order or not.\n        (uint256 _spotPrice, uint256 _histPrice, address _baseAsset, address _quoteAsset) = oracle.latestPrices(\n            IOrigamiOracle.PriceType.SPOT_PRICE,\n            OrigamiMath.Rounding.ROUND_UP,\n            IOrigamiOracle.PriceType.HISTORIC_PRICE,\n            OrigamiMath.Rounding.ROUND_UP\n        );\n        \n        // Whether the expected 'base' asset of the oracle is indeed the base asset.\n        // If not, then the delta and denominator is switched\n        bool _inQuotedOrder;\n        if (_baseAsset == expectedBaseAsset) {\n            _inQuotedOrder = true;\n        } else if (_quoteAsset != expectedBaseAsset) {\n            revert CommonEventsAndErrors.InvalidToken(expectedBaseAsset);\n        }\n\n        uint256 _delta;\n        uint256 _denominator;\n        if (feeType == FeeType.DEPOSIT_FEE) {\n            // If spot price is > than the expected historic, then they are exiting\n            // at a price better than expected. The exit fee is based off the relative\n            // difference of the expected spotPrice - historicPrice.\n            // Or opposite if the oracle order is inverted\n            unchecked {\n                if (_inQuotedOrder) {\n                    if (_spotPrice < _histPrice) {\n                        (_delta, _denominator) = (_histPrice - _spotPrice, _histPrice);\n                    }\n                } else {\n                    if (_spotPrice > _histPrice) {\n                        (_delta, _denominator) = (_spotPrice - _histPrice, _spotPrice);\n                    }\n                }\n            }\n        } else {\n            // If spot price is > than the expected historic, then they are exiting\n            // at a price better than expected. The exit fee is based off the relative\n            // difference of the expected spotPrice - historicPrice.\n            // Or opposite if the oracle order is inverted\n            unchecked {\n                if (_inQuotedOrder) {\n                    if (_spotPrice > _histPrice) {\n                        (_delta, _denominator) = (_spotPrice - _histPrice, _histPrice);\n                    }\n                } else {\n                    if (_spotPrice < _histPrice) {\n                        (_delta, _denominator) = (_histPrice - _spotPrice, _spotPrice);\n                    }\n                }\n            }\n        }\n\n        // If no delta, just return the min fee\n        if (_delta == 0) {\n            return minFeeBps;\n        }\n\n        // Relative diff multiply by a leverage factor to match the worst case lovToken\n        // effective exposure\n        // Result is in basis points, since `feeLeverageFactor` has 4dp precision\n        uint256 _fee = _delta.mulDiv(\n            feeLeverageFactor,\n            _denominator,\n            OrigamiMath.Rounding.ROUND_UP\n        );\n\n        // Use the maximum of the calculated fee and a pre-set minimum.\n        return minFeeBps > _fee ? minFeeBps : _fee;\n    }\n}\n"
      },
      "contracts/libraries/OrigamiMath.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (libraries/OrigamiMath.sol)\n\nimport { mulDiv as prbMulDiv, PRBMath_MulDiv_Overflow } from \"@prb/math/src/Common.sol\";\nimport { CommonEventsAndErrors } from \"contracts/libraries/CommonEventsAndErrors.sol\";\n\n/**\n * @notice Utilities to operate on fixed point math multipliation and division\n * taking rounding into consideration\n */\nlibrary OrigamiMath {\n    enum Rounding {\n        ROUND_DOWN,\n        ROUND_UP\n    }\n\n    uint256 public constant BASIS_POINTS_DIVISOR = 10_000;\n\n    function scaleUp(uint256 amount, uint256 scalar) internal pure returns (uint256) {\n        // Special case for scalar == 1, as it's common for token amounts to not need\n        // scaling if decimal places are the same\n        return scalar == 1 ? amount : amount * scalar;\n    }\n\n    function scaleDown(\n        uint256 amount, \n        uint256 scalar, \n        Rounding roundingMode\n    ) internal pure returns (uint256 result) {\n        // Special case for scalar == 1, as it's common for token amounts to not need\n        // scaling if decimal places are the same\n        unchecked {\n            if (scalar == 1) {\n                result = amount;\n            } else if (roundingMode == Rounding.ROUND_DOWN) {\n                result = amount / scalar;\n            } else {\n                // ROUND_UP uses the same logic as OZ Math.ceilDiv()\n                result = amount == 0 ? 0 : (amount - 1) / scalar + 1;\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision,\n     * rounding up\n     */\n    function mulDiv(\n        uint256 x, \n        uint256 y, \n        uint256 denominator,\n        Rounding roundingMode\n    ) internal pure returns (uint256 result) {\n        result = prbMulDiv(x, y, denominator);\n        if (roundingMode == Rounding.ROUND_UP) {\n            if (mulmod(x, y, denominator) != 0) {\n                if (result < type(uint256).max) {\n                    unchecked {\n                        result = result + 1;\n                    }\n                } else {\n                    revert PRBMath_MulDiv_Overflow(x, y, denominator);\n                }\n            }\n        }\n    }\n\n    function subtractBps(\n        uint256 inputAmount, \n        uint256 basisPoints,\n        Rounding roundingMode\n    ) internal pure returns (uint256 result) {\n        uint256 numeratorBps;\n        unchecked {\n            numeratorBps = BASIS_POINTS_DIVISOR - basisPoints;\n        }\n\n        result = basisPoints < BASIS_POINTS_DIVISOR\n            ? mulDiv(\n                inputAmount,\n                numeratorBps, \n                BASIS_POINTS_DIVISOR, \n                roundingMode\n            ) : 0;\n    }\n\n    function addBps(\n        uint256 inputAmount,\n        uint256 basisPoints,\n        Rounding roundingMode\n    ) internal pure returns (uint256 result) {\n        uint256 numeratorBps;\n        unchecked {\n            numeratorBps = BASIS_POINTS_DIVISOR + basisPoints;\n        }\n\n        // Round up for max amounts out expected\n        result = mulDiv(\n            inputAmount,\n            numeratorBps, \n            BASIS_POINTS_DIVISOR, \n            roundingMode\n        );\n    }\n\n    /**\n     * @notice Split the `inputAmount` into two parts based on the `basisPoints` fraction.\n     * eg: 3333 BPS (33.3%) can be used to split an input amount of 600 into: (result=400, removed=200).\n     * @dev The rounding mode is applied to the `result`\n     */\n    function splitSubtractBps(\n        uint256 inputAmount, \n        uint256 basisPoints,\n        Rounding roundingMode\n    ) internal pure returns (uint256 result, uint256 removed) {\n        result = subtractBps(inputAmount, basisPoints, roundingMode);\n        unchecked {\n            removed = inputAmount - result;\n        }\n    }\n\n    /**\n     * @notice Reverse the fractional amount of an input.\n     * eg: For 3333 BPS (33.3%) and the remainder=400, the result is 600\n     */\n    function inverseSubtractBps(\n        uint256 remainderAmount, \n        uint256 basisPoints,\n        Rounding roundingMode\n    ) internal pure returns (uint256 result) {\n        if (basisPoints == 0) return remainderAmount; // gas shortcut for 0\n        if (basisPoints >= BASIS_POINTS_DIVISOR) revert CommonEventsAndErrors.InvalidParam();\n\n        uint256 denominatorBps;\n        unchecked {\n            denominatorBps = BASIS_POINTS_DIVISOR - basisPoints;\n        }\n        result = mulDiv(\n            remainderAmount,\n            BASIS_POINTS_DIVISOR, \n            denominatorBps, \n            roundingMode\n        );\n    }\n\n    /**\n     * @notice Calculate the relative difference of a value to a reference\n     * @dev `value` and `referenceValue` must have the same precision\n     * The denominator is always the referenceValue\n     */\n    function relativeDifferenceBps(\n        uint256 value,\n        uint256 referenceValue,\n        Rounding roundingMode\n    ) internal pure returns (uint256) {\n        if (referenceValue == 0) revert CommonEventsAndErrors.InvalidParam();\n\n        uint256 absDelta;\n        unchecked {\n            absDelta = value < referenceValue\n                ? referenceValue - value\n                : value - referenceValue;\n        }\n\n        return mulDiv(\n            absDelta,\n            BASIS_POINTS_DIVISOR,\n            referenceValue,\n            roundingMode\n        );\n    }\n}\n"
      },
      "contracts/libraries/Range.sol": {
        "content": "pragma solidity 0.8.19;\n// SPDX-License-Identifier: AGPL-3.0-or-later\n// Origami (libraries/Range.sol)\n\n/**\n * @notice A helper library to track a valid range from floor <= x <= ceiling\n */\nlibrary Range {\n    error InvalidRange(uint128 floor, uint128 ceiling);\n\n    struct Data {\n        uint128 floor;\n        uint128 ceiling;\n    }\n\n    function set(Data storage range, uint128 floor, uint128 ceiling) internal {\n        if (floor > ceiling) {\n            revert InvalidRange(floor, ceiling);\n        }\n        range.floor = floor;\n        range.ceiling = ceiling;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 10000
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}