creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  function getRoundData(\n    uint80 _roundId\n  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n  function latestRoundData()\n    external\n    view\n    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"
      },
      "@mean-finance/uniswap-v3-oracle/solidity/interfaces/IStaticOracle.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\n\npragma solidity >=0.7.6 <0.9.0;\n\nimport '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol';\n\n/// @title Uniswap V3 Static Oracle\n/// @notice Oracle contract for calculating price quoting against Uniswap V3\ninterface IStaticOracle {\n  /// @notice Returns the address of the Uniswap V3 factory\n  /// @dev This value is assigned during deployment and cannot be changed\n  /// @return The address of the Uniswap V3 factory\n  function UNISWAP_V3_FACTORY() external view returns (IUniswapV3Factory);\n\n  /// @notice Returns how many observations are needed per minute in Uniswap V3 oracles, on the deployed chain\n  /// @dev This value is assigned during deployment and cannot be changed\n  /// @return Number of observation that are needed per minute\n  function CARDINALITY_PER_MINUTE() external view returns (uint8);\n\n  /// @notice Returns all supported fee tiers\n  /// @return The supported fee tiers\n  function supportedFeeTiers() external view returns (uint24[] memory);\n\n  /// @notice Returns whether a specific pair can be supported by the oracle\n  /// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order\n  /// @return Whether the given pair can be supported by the oracle\n  function isPairSupported(address tokenA, address tokenB) external view returns (bool);\n\n  /// @notice Returns all existing pools for the given pair\n  /// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order\n  /// @return All existing pools for the given pair\n  function getAllPoolsForPair(address tokenA, address tokenB) external view returns (address[] memory);\n\n  /// @notice Returns a quote, based on the given tokens and amount, by querying all of the pair's pools\n  /// @dev If some pools are not configured correctly for the given period, then they will be ignored\n  /// @dev Will revert if there are no pools available/configured for the pair and period combination\n  /// @param baseAmount Amount of token to be converted\n  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination\n  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination\n  /// @param period Number of seconds from which to calculate the TWAP\n  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken\n  /// @return queriedPools The pools that were queried to calculate the quote\n  function quoteAllAvailablePoolsWithTimePeriod(\n    uint128 baseAmount,\n    address baseToken,\n    address quoteToken,\n    uint32 period\n  ) external view returns (uint256 quoteAmount, address[] memory queriedPools);\n\n  /// @notice Returns a quote, based on the given tokens and amount, by querying only the specified fee tiers\n  /// @dev Will revert if the pair does not have a pool for one of the given fee tiers, or if one of the pools\n  /// is not prepared/configured correctly for the given period\n  /// @param baseAmount Amount of token to be converted\n  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination\n  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination\n  /// @param feeTiers The fee tiers to consider when calculating the quote\n  /// @param period Number of seconds from which to calculate the TWAP\n  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken\n  /// @return queriedPools The pools that were queried to calculate the quote\n  function quoteSpecificFeeTiersWithTimePeriod(\n    uint128 baseAmount,\n    address baseToken,\n    address quoteToken,\n    uint24[] calldata feeTiers,\n    uint32 period\n  ) external view returns (uint256 quoteAmount, address[] memory queriedPools);\n\n  /// @notice Returns a quote, based on the given tokens and amount, by querying only the specified pools\n  /// @dev Will revert if one of the pools is not prepared/configured correctly for the given period\n  /// @param baseAmount Amount of token to be converted\n  /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination\n  /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination\n  /// @param pools The pools to consider when calculating the quote\n  /// @param period Number of seconds from which to calculate the TWAP\n  /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken\n  function quoteSpecificPoolsWithTimePeriod(\n    uint128 baseAmount,\n    address baseToken,\n    address quoteToken,\n    address[] calldata pools,\n    uint32 period\n  ) external view returns (uint256 quoteAmount);\n\n  /// @notice Will initialize all existing pools for the given pair, so that they can be queried with the given period in the future\n  /// @dev Will revert if there are no pools available for the pair and period combination\n  /// @param tokenA One of the pair's tokens\n  /// @param tokenB The other of the pair's tokens\n  /// @param period The period that will be guaranteed when quoting\n  /// @return preparedPools The pools that were prepared\n  function prepareAllAvailablePoolsWithTimePeriod(\n    address tokenA,\n    address tokenB,\n    uint32 period\n  ) external returns (address[] memory preparedPools);\n\n  /// @notice Will initialize the pair's pools with the specified fee tiers, so that they can be queried with the given period in the future\n  /// @dev Will revert if the pair does not have a pool for a given fee tier\n  /// @param tokenA One of the pair's tokens\n  /// @param tokenB The other of the pair's tokens\n  /// @param feeTiers The fee tiers to consider when searching for the pair's pools\n  /// @param period The period that will be guaranteed when quoting\n  /// @return preparedPools The pools that were prepared\n  function prepareSpecificFeeTiersWithTimePeriod(\n    address tokenA,\n    address tokenB,\n    uint24[] calldata feeTiers,\n    uint32 period\n  ) external returns (address[] memory preparedPools);\n\n  /// @notice Will initialize all given pools, so that they can be queried with the given period in the future\n  /// @param pools The pools to initialize\n  /// @param period The period that will be guaranteed when quoting\n  function prepareSpecificPoolsWithTimePeriod(address[] calldata pools, uint32 period) external;\n\n  /// @notice Will increase observations for all existing pools for the given pair, so they start accruing information for twap calculations\n  /// @dev Will revert if there are no pools available for the pair and period combination\n  /// @param tokenA One of the pair's tokens\n  /// @param tokenB The other of the pair's tokens\n  /// @param cardinality The cardinality that will be guaranteed when quoting\n  /// @return preparedPools The pools that were prepared\n  function prepareAllAvailablePoolsWithCardinality(\n    address tokenA,\n    address tokenB,\n    uint16 cardinality\n  ) external returns (address[] memory preparedPools);\n\n  /// @notice Will increase the pair's pools with the specified fee tiers observations, so they start accruing information for twap calculations\n  /// @dev Will revert if the pair does not have a pool for a given fee tier\n  /// @param tokenA One of the pair's tokens\n  /// @param tokenB The other of the pair's tokens\n  /// @param feeTiers The fee tiers to consider when searching for the pair's pools\n  /// @param cardinality The cardinality that will be guaranteed when quoting\n  /// @return preparedPools The pools that were prepared\n  function prepareSpecificFeeTiersWithCardinality(\n    address tokenA,\n    address tokenB,\n    uint24[] calldata feeTiers,\n    uint16 cardinality\n  ) external returns (address[] memory preparedPools);\n\n  /// @notice Will increase all given pools observations, so they start accruing information for twap calculations\n  /// @param pools The pools to initialize\n  /// @param cardinality The cardinality that will be guaranteed when quoting\n  function prepareSpecificPoolsWithCardinality(address[] calldata pools, uint16 cardinality) external;\n\n  /// @notice Adds support for a new fee tier\n  /// @dev Will revert if the given tier is invalid, or already supported\n  /// @param feeTier The new fee tier to add\n  function addNewFeeTier(uint24 feeTier) external;\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable2Step.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n        _transferOwnership(sender);\n    }\n}\n"
      },
      "@openzeppelin/contracts/interfaces/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\n"
      },
      "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the default value returned by this function, unless\n     * it's overridden.\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(address from, address to, uint256 amount) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n"
      },
      "@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"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\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 {\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                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\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 {\n                // Compute remainder using mulmod.\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            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\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            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SafeCast.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     *\n     * _Available since v3.0._\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     *\n     * _Available since v3.0._\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/libraries/Errors.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nlibrary Errors {\n    // APPROX\n    error ApproxFail();\n    error ApproxParamsInvalid(uint256 guessMin, uint256 guessMax, uint256 eps);\n    error ApproxBinarySearchInputInvalid(\n        uint256 approxGuessMin, uint256 approxGuessMax, uint256 minGuessMin, uint256 maxGuessMax\n    );\n\n    // MARKET + MARKET MATH CORE\n    error MarketExpired();\n    error MarketZeroAmountsInput();\n    error MarketZeroAmountsOutput();\n    error MarketZeroLnImpliedRate();\n    error MarketInsufficientPtForTrade(int256 currentAmount, int256 requiredAmount);\n    error MarketInsufficientPtReceived(uint256 actualBalance, uint256 requiredBalance);\n    error MarketInsufficientSyReceived(uint256 actualBalance, uint256 requiredBalance);\n    error MarketZeroTotalPtOrTotalAsset(int256 totalPt, int256 totalAsset);\n    error MarketExchangeRateBelowOne(int256 exchangeRate);\n    error MarketProportionMustNotEqualOne();\n    error MarketRateScalarBelowZero(int256 rateScalar);\n    error MarketScalarRootBelowZero(int256 scalarRoot);\n    error MarketProportionTooHigh(int256 proportion, int256 maxProportion);\n\n    error OracleUninitialized();\n    error OracleTargetTooOld(uint32 target, uint32 oldest);\n    error OracleZeroCardinality();\n\n    error MarketFactoryExpiredPt();\n    error MarketFactoryInvalidPt();\n    error MarketFactoryMarketExists();\n\n    error MarketFactoryLnFeeRateRootTooHigh(uint80 lnFeeRateRoot, uint256 maxLnFeeRateRoot);\n    error MarketFactoryReserveFeePercentTooHigh(uint8 reserveFeePercent, uint8 maxReserveFeePercent);\n    error MarketFactoryZeroTreasury();\n    error MarketFactoryInitialAnchorTooLow(int256 initialAnchor, int256 minInitialAnchor);\n\n    // ROUTER\n    error RouterInsufficientLpOut(uint256 actualLpOut, uint256 requiredLpOut);\n    error RouterInsufficientSyOut(uint256 actualSyOut, uint256 requiredSyOut);\n    error RouterInsufficientPtOut(uint256 actualPtOut, uint256 requiredPtOut);\n    error RouterInsufficientYtOut(uint256 actualYtOut, uint256 requiredYtOut);\n    error RouterInsufficientPYOut(uint256 actualPYOut, uint256 requiredPYOut);\n    error RouterInsufficientTokenOut(uint256 actualTokenOut, uint256 requiredTokenOut);\n    error RouterInsufficientSyRepay(uint256 actualSyRepay, uint256 requiredSyRepay);\n    error RouterInsufficientPtRepay(uint256 actualPtRepay, uint256 requiredPtRepay);\n    error RouterNotAllSyUsed(uint256 netSyDesired, uint256 netSyUsed);\n\n    error RouterTimeRangeZero();\n    error RouterCallbackNotPendleMarket(address caller);\n    error RouterInvalidAction(bytes4 selector);\n    error RouterInvalidFacet(address facet);\n\n    error RouterKyberSwapDataZero();\n\n    error CallThenRevertError(bool success, bytes res);\n\n    // YIELD CONTRACT\n    error YCExpired();\n    error YCNotExpired();\n    error YieldContractInsufficientSy(uint256 actualSy, uint256 requiredSy);\n    error YCNothingToRedeem();\n    error YCPostExpiryDataNotSet();\n    error YCNoFloatingSy();\n\n    // YieldFactory\n    error YCFactoryInvalidExpiry();\n    error YCFactoryYieldContractExisted();\n    error YCFactoryZeroExpiryDivisor();\n    error YCFactoryZeroTreasury();\n    error YCFactoryInterestFeeRateTooHigh(uint256 interestFeeRate, uint256 maxInterestFeeRate);\n    error YCFactoryRewardFeeRateTooHigh(uint256 newRewardFeeRate, uint256 maxRewardFeeRate);\n\n    // SY\n    error SYInvalidTokenIn(address token);\n    error SYInvalidTokenOut(address token);\n    error SYZeroDeposit();\n    error SYZeroRedeem();\n    error SYInsufficientSharesOut(uint256 actualSharesOut, uint256 requiredSharesOut);\n    error SYInsufficientTokenOut(uint256 actualTokenOut, uint256 requiredTokenOut);\n\n    // SY-specific\n    error SYQiTokenMintFailed(uint256 errCode);\n    error SYQiTokenRedeemFailed(uint256 errCode);\n    error SYQiTokenRedeemRewardsFailed(uint256 rewardAccruedType0, uint256 rewardAccruedType1);\n    error SYQiTokenBorrowRateTooHigh(uint256 borrowRate, uint256 borrowRateMax);\n\n    error SYCurveInvalidPid();\n    error SYCurve3crvPoolNotFound();\n\n    error SYApeDepositAmountTooSmall(uint256 amountDeposited);\n    error SYBalancerInvalidPid();\n    error SYInvalidRewardToken(address token);\n\n    error SYStargateRedeemCapExceeded(uint256 amountLpDesired, uint256 amountLpRedeemable);\n\n    error SYBalancerReentrancy();\n\n    error NotFromTrustedRemote(uint16 srcChainId, bytes path);\n\n    // Liquidity Mining\n    error VCInactivePool(address pool);\n    error VCPoolAlreadyActive(address pool);\n    error VCZeroVePendle(address user);\n    error VCExceededMaxWeight(uint256 totalWeight, uint256 maxWeight);\n    error VCEpochNotFinalized(uint256 wTime);\n    error VCPoolAlreadyAddAndRemoved(address pool);\n\n    error VEInvalidNewExpiry(uint256 newExpiry);\n    error VEExceededMaxLockTime();\n    error VEInsufficientLockTime();\n    error VENotAllowedReduceExpiry();\n    error VEZeroAmountLocked();\n    error VEPositionNotExpired();\n    error VEZeroPosition();\n    error VEZeroSlope(uint128 bias, uint128 slope);\n    error VEReceiveOldSupply(uint256 msgTime);\n\n    error GCNotPendleMarket(address caller);\n    error GCNotVotingController(address caller);\n\n    error InvalidWTime(uint256 wTime);\n    error ExpiryInThePast(uint256 expiry);\n    error ChainNotSupported(uint256 chainId);\n\n    error FDTotalAmountFundedNotMatch(uint256 actualTotalAmount, uint256 expectedTotalAmount);\n    error FDEpochLengthMismatch();\n    error FDInvalidPool(address pool);\n    error FDPoolAlreadyExists(address pool);\n    error FDInvalidNewFinishedEpoch(uint256 oldFinishedEpoch, uint256 newFinishedEpoch);\n    error FDInvalidStartEpoch(uint256 startEpoch);\n    error FDInvalidWTimeFund(uint256 lastFunded, uint256 wTime);\n    error FDFutureFunding(uint256 lastFunded, uint256 currentWTime);\n\n    error BDInvalidEpoch(uint256 epoch, uint256 startTime);\n\n    // Cross-Chain\n    error MsgNotFromSendEndpoint(uint16 srcChainId, bytes path);\n    error MsgNotFromReceiveEndpoint(address sender);\n    error InsufficientFeeToSendMsg(uint256 currentFee, uint256 requiredFee);\n    error ApproxDstExecutionGasNotSet();\n    error InvalidRetryData();\n\n    // GENERIC MSG\n    error ArrayLengthMismatch();\n    error ArrayEmpty();\n    error ArrayOutOfBounds();\n    error ZeroAddress();\n    error FailedToSendEther();\n    error InvalidMerkleProof();\n\n    error OnlyLayerZeroEndpoint();\n    error OnlyYT();\n    error OnlyYCFactory();\n    error OnlyWhitelisted();\n\n    // Swap Aggregator\n    error SAInsufficientTokenIn(address tokenIn, uint256 amountExpected, uint256 amountActual);\n    error UnsupportedSelector(uint256 aggregatorType, bytes4 selector);\n}\n"
      },
      "@pendle/core-v2/contracts/core/libraries/math/LogExpMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n\n// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npragma solidity ^0.8.0;\n\n/* solhint-disable */\n\n/**\n * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).\n *\n * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural\n * exponentiation and logarithm (where the base is Euler's number).\n *\n * @author Fernando Martinelli - @fernandomartinelli\n * @author Sergio Yuhjtman - @sergioyuhjtman\n * @author Daniel Fernandez - @dmf7z\n */\nlibrary LogExpMath {\n    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying\n    // two numbers, and multiply by ONE when dividing them.\n\n    // All arguments and return values are 18 decimal fixed point numbers.\n    int256 constant ONE_18 = 1e18;\n\n    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the\n    // case of ln36, 36 decimals.\n    int256 constant ONE_20 = 1e20;\n    int256 constant ONE_36 = 1e36;\n\n    // The domain of natural exponentiation is bound by the word size and number of decimals used.\n    //\n    // Because internally the result will be stored using 20 decimals, the largest possible result is\n    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.\n    // The smallest possible result is 10^(-18), which makes largest negative argument\n    // ln(10^(-18)) = -41.446531673892822312.\n    // We use 130.0 and -41.0 to have some safety margin.\n    int256 constant MAX_NATURAL_EXPONENT = 130e18;\n    int256 constant MIN_NATURAL_EXPONENT = -41e18;\n\n    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point\n    // 256 bit integer.\n    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;\n    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;\n\n    uint256 constant MILD_EXPONENT_BOUND = 2 ** 254 / uint256(ONE_20);\n\n    // 18 decimal constants\n    int256 constant x0 = 128000000000000000000; // 2ˆ7\n    int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)\n    int256 constant x1 = 64000000000000000000; // 2ˆ6\n    int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)\n\n    // 20 decimal constants\n    int256 constant x2 = 3200000000000000000000; // 2ˆ5\n    int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)\n    int256 constant x3 = 1600000000000000000000; // 2ˆ4\n    int256 constant a3 = 888611052050787263676000000; // eˆ(x3)\n    int256 constant x4 = 800000000000000000000; // 2ˆ3\n    int256 constant a4 = 298095798704172827474000; // eˆ(x4)\n    int256 constant x5 = 400000000000000000000; // 2ˆ2\n    int256 constant a5 = 5459815003314423907810; // eˆ(x5)\n    int256 constant x6 = 200000000000000000000; // 2ˆ1\n    int256 constant a6 = 738905609893065022723; // eˆ(x6)\n    int256 constant x7 = 100000000000000000000; // 2ˆ0\n    int256 constant a7 = 271828182845904523536; // eˆ(x7)\n    int256 constant x8 = 50000000000000000000; // 2ˆ-1\n    int256 constant a8 = 164872127070012814685; // eˆ(x8)\n    int256 constant x9 = 25000000000000000000; // 2ˆ-2\n    int256 constant a9 = 128402541668774148407; // eˆ(x9)\n    int256 constant x10 = 12500000000000000000; // 2ˆ-3\n    int256 constant a10 = 113314845306682631683; // eˆ(x10)\n    int256 constant x11 = 6250000000000000000; // 2ˆ-4\n    int256 constant a11 = 106449445891785942956; // eˆ(x11)\n\n    /**\n     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.\n     *\n     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.\n     */\n    function exp(int256 x) internal pure returns (int256) {\n        unchecked {\n            require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, \"Invalid exponent\");\n\n            if (x < 0) {\n                // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it\n                // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).\n                // Fixed point division requires multiplying by ONE_18.\n                return ((ONE_18 * ONE_18) / exp(-x));\n            }\n\n            // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,\n            // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7\n            // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the\n            // decomposition.\n            // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this\n            // decomposition, which will be lower than the smallest x_n.\n            // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.\n            // We mutate x by subtracting x_n, making it the remainder of the decomposition.\n\n            // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause\n            // intermediate overflows. Instead we store them as plain integers, with 0 decimals.\n            // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the\n            // decomposition.\n\n            // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct\n            // it and compute the accumulated product.\n\n            int256 firstAN;\n            if (x >= x0) {\n                x -= x0;\n                firstAN = a0;\n            } else if (x >= x1) {\n                x -= x1;\n                firstAN = a1;\n            } else {\n                firstAN = 1; // One with no decimal places\n            }\n\n            // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the\n            // smaller terms.\n            x *= 100;\n\n            // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point\n            // one. Recall that fixed point multiplication requires dividing by ONE_20.\n            int256 product = ONE_20;\n\n            if (x >= x2) {\n                x -= x2;\n                product = (product * a2) / ONE_20;\n            }\n            if (x >= x3) {\n                x -= x3;\n                product = (product * a3) / ONE_20;\n            }\n            if (x >= x4) {\n                x -= x4;\n                product = (product * a4) / ONE_20;\n            }\n            if (x >= x5) {\n                x -= x5;\n                product = (product * a5) / ONE_20;\n            }\n            if (x >= x6) {\n                x -= x6;\n                product = (product * a6) / ONE_20;\n            }\n            if (x >= x7) {\n                x -= x7;\n                product = (product * a7) / ONE_20;\n            }\n            if (x >= x8) {\n                x -= x8;\n                product = (product * a8) / ONE_20;\n            }\n            if (x >= x9) {\n                x -= x9;\n                product = (product * a9) / ONE_20;\n            }\n\n            // x10 and x11 are unnecessary here since we have high enough precision already.\n\n            // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series\n            // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).\n\n            int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.\n            int256 term; // Each term in the sum, where the nth term is (x^n / n!).\n\n            // The first term is simply x.\n            term = x;\n            seriesSum += term;\n\n            // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,\n            // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.\n\n            term = ((term * x) / ONE_20) / 2;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 3;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 4;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 5;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 6;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 7;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 8;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 9;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 10;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 11;\n            seriesSum += term;\n\n            term = ((term * x) / ONE_20) / 12;\n            seriesSum += term;\n\n            // 12 Taylor terms are sufficient for 18 decimal precision.\n\n            // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor\n            // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply\n            // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),\n            // and then drop two digits to return an 18 decimal value.\n\n            return (((product * seriesSum) / ONE_20) * firstAN) / 100;\n        }\n    }\n\n    /**\n     * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n     */\n    function ln(int256 a) internal pure returns (int256) {\n        unchecked {\n            // The real natural logarithm is not defined for negative numbers or zero.\n            require(a > 0, \"out of bounds\");\n            if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {\n                return _ln_36(a) / ONE_18;\n            } else {\n                return _ln(a);\n            }\n        }\n    }\n\n    /**\n     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.\n     *\n     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.\n     */\n    function pow(uint256 x, uint256 y) internal pure returns (uint256) {\n        unchecked {\n            if (y == 0) {\n                // We solve the 0^0 indetermination by making it equal one.\n                return uint256(ONE_18);\n            }\n\n            if (x == 0) {\n                return 0;\n            }\n\n            // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to\n            // arrive at that r`esult. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means\n            // x^y = exp(y * ln(x)).\n\n            // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.\n            require(x < 2 ** 255, \"x out of bounds\");\n            int256 x_int256 = int256(x);\n\n            // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In\n            // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.\n\n            // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.\n            require(y < MILD_EXPONENT_BOUND, \"y out of bounds\");\n            int256 y_int256 = int256(y);\n\n            int256 logx_times_y;\n            if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {\n                int256 ln_36_x = _ln_36(x_int256);\n\n                // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just\n                // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal\n                // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the\n                // (downscaled) last 18 decimals.\n                logx_times_y = ((ln_36_x / ONE_18) *\n                    y_int256 +\n                    ((ln_36_x % ONE_18) * y_int256) /\n                    ONE_18);\n            } else {\n                logx_times_y = _ln(x_int256) * y_int256;\n            }\n            logx_times_y /= ONE_18;\n\n            // Finally, we compute exp(y * ln(x)) to arrive at x^y\n            require(\n                MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,\n                \"product out of bounds\"\n            );\n\n            return uint256(exp(logx_times_y));\n        }\n    }\n\n    /**\n     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n     */\n    function _ln(int256 a) private pure returns (int256) {\n        unchecked {\n            if (a < ONE_18) {\n                // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less\n                // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.\n                // Fixed point division requires multiplying by ONE_18.\n                return (-_ln((ONE_18 * ONE_18) / a));\n            }\n\n            // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which\n            // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,\n            // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot\n            // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.\n            // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this\n            // decomposition, which will be lower than the smallest a_n.\n            // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.\n            // We mutate a by subtracting a_n, making it the remainder of the decomposition.\n\n            // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point\n            // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by\n            // ONE_18 to convert them to fixed point.\n            // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide\n            // by it and compute the accumulated sum.\n\n            int256 sum = 0;\n            if (a >= a0 * ONE_18) {\n                a /= a0; // Integer, not fixed point division\n                sum += x0;\n            }\n\n            if (a >= a1 * ONE_18) {\n                a /= a1; // Integer, not fixed point division\n                sum += x1;\n            }\n\n            // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.\n            sum *= 100;\n            a *= 100;\n\n            // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.\n\n            if (a >= a2) {\n                a = (a * ONE_20) / a2;\n                sum += x2;\n            }\n\n            if (a >= a3) {\n                a = (a * ONE_20) / a3;\n                sum += x3;\n            }\n\n            if (a >= a4) {\n                a = (a * ONE_20) / a4;\n                sum += x4;\n            }\n\n            if (a >= a5) {\n                a = (a * ONE_20) / a5;\n                sum += x5;\n            }\n\n            if (a >= a6) {\n                a = (a * ONE_20) / a6;\n                sum += x6;\n            }\n\n            if (a >= a7) {\n                a = (a * ONE_20) / a7;\n                sum += x7;\n            }\n\n            if (a >= a8) {\n                a = (a * ONE_20) / a8;\n                sum += x8;\n            }\n\n            if (a >= a9) {\n                a = (a * ONE_20) / a9;\n                sum += x9;\n            }\n\n            if (a >= a10) {\n                a = (a * ONE_20) / a10;\n                sum += x10;\n            }\n\n            if (a >= a11) {\n                a = (a * ONE_20) / a11;\n                sum += x11;\n            }\n\n            // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series\n            // that converges rapidly for values of `a` close to one - the same one used in ln_36.\n            // Let z = (a - 1) / (a + 1).\n            // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n            // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires\n            // division by ONE_20.\n            int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);\n            int256 z_squared = (z * z) / ONE_20;\n\n            // num is the numerator of the series: the z^(2 * n + 1) term\n            int256 num = z;\n\n            // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n            int256 seriesSum = num;\n\n            // In each step, the numerator is multiplied by z^2\n            num = (num * z_squared) / ONE_20;\n            seriesSum += num / 3;\n\n            num = (num * z_squared) / ONE_20;\n            seriesSum += num / 5;\n\n            num = (num * z_squared) / ONE_20;\n            seriesSum += num / 7;\n\n            num = (num * z_squared) / ONE_20;\n            seriesSum += num / 9;\n\n            num = (num * z_squared) / ONE_20;\n            seriesSum += num / 11;\n\n            // 6 Taylor terms are sufficient for 36 decimal precision.\n\n            // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)\n            seriesSum *= 2;\n\n            // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both\n            // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal\n            // value.\n\n            return (sum + seriesSum) / 100;\n        }\n    }\n\n    /**\n     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,\n     * for x close to one.\n     *\n     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.\n     */\n    function _ln_36(int256 x) private pure returns (int256) {\n        unchecked {\n            // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits\n            // worthwhile.\n\n            // First, we transform x to a 36 digit fixed point value.\n            x *= ONE_18;\n\n            // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).\n            // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n            // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires\n            // division by ONE_36.\n            int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);\n            int256 z_squared = (z * z) / ONE_36;\n\n            // num is the numerator of the series: the z^(2 * n + 1) term\n            int256 num = z;\n\n            // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n            int256 seriesSum = num;\n\n            // In each step, the numerator is multiplied by z^2\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 3;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 5;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 7;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 9;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 11;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 13;\n\n            num = (num * z_squared) / ONE_36;\n            seriesSum += num / 15;\n\n            // 8 Taylor terms are sufficient for 36 decimal precision.\n\n            // All that remains is multiplying by 2 (non fixed point).\n            return seriesSum * 2;\n        }\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/libraries/math/PMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\npragma solidity ^0.8.0;\n\n/* solhint-disable private-vars-leading-underscore, reason-string */\n\nlibrary PMath {\n    uint256 internal constant ONE = 1e18; // 18 decimal places\n    int256 internal constant IONE = 1e18; // 18 decimal places\n\n    function subMax0(uint256 a, uint256 b) internal pure returns (uint256) {\n        unchecked {\n            return (a >= b ? a - b : 0);\n        }\n    }\n\n    function subNoNeg(int256 a, int256 b) internal pure returns (int256) {\n        require(a >= b, \"negative\");\n        return a - b; // no unchecked since if b is very negative, a - b might overflow\n    }\n\n    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 product = a * b;\n        unchecked {\n            return product / ONE;\n        }\n    }\n\n    function mulDown(int256 a, int256 b) internal pure returns (int256) {\n        int256 product = a * b;\n        unchecked {\n            return product / IONE;\n        }\n    }\n\n    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 aInflated = a * ONE;\n        unchecked {\n            return aInflated / b;\n        }\n    }\n\n    function divDown(int256 a, int256 b) internal pure returns (int256) {\n        int256 aInflated = a * IONE;\n        unchecked {\n            return aInflated / b;\n        }\n    }\n\n    function rawDivUp(uint256 a, uint256 b) internal pure returns (uint256) {\n        return (a + b - 1) / b;\n    }\n\n    // @author Uniswap\n    function sqrt(uint256 y) internal pure returns (uint256 z) {\n        if (y > 3) {\n            z = y;\n            uint256 x = y / 2 + 1;\n            while (x < z) {\n                z = x;\n                x = (y / x + x) / 2;\n            }\n        } else if (y != 0) {\n            z = 1;\n        }\n    }\n\n    function square(uint256 x) internal pure returns (uint256) {\n        return x * x;\n    }\n\n    function squareDown(uint256 x) internal pure returns (uint256) {\n        return mulDown(x, x);\n    }\n\n    function abs(int256 x) internal pure returns (uint256) {\n        return uint256(x > 0 ? x : -x);\n    }\n\n    function neg(int256 x) internal pure returns (int256) {\n        return x * (-1);\n    }\n\n    function neg(uint256 x) internal pure returns (int256) {\n        return Int(x) * (-1);\n    }\n\n    function max(uint256 x, uint256 y) internal pure returns (uint256) {\n        return (x > y ? x : y);\n    }\n\n    function max(int256 x, int256 y) internal pure returns (int256) {\n        return (x > y ? x : y);\n    }\n\n    function min(uint256 x, uint256 y) internal pure returns (uint256) {\n        return (x < y ? x : y);\n    }\n\n    function min(int256 x, int256 y) internal pure returns (int256) {\n        return (x < y ? x : y);\n    }\n\n    /*///////////////////////////////////////////////////////////////\n                               SIGNED CASTS\n    //////////////////////////////////////////////////////////////*/\n\n    function Int(uint256 x) internal pure returns (int256) {\n        require(x <= uint256(type(int256).max));\n        return int256(x);\n    }\n\n    function Int128(int256 x) internal pure returns (int128) {\n        require(type(int128).min <= x && x <= type(int128).max);\n        return int128(x);\n    }\n\n    function Int128(uint256 x) internal pure returns (int128) {\n        return Int128(Int(x));\n    }\n\n    /*///////////////////////////////////////////////////////////////\n                               UNSIGNED CASTS\n    //////////////////////////////////////////////////////////////*/\n\n    function Uint(int256 x) internal pure returns (uint256) {\n        require(x >= 0);\n        return uint256(x);\n    }\n\n    function Uint32(uint256 x) internal pure returns (uint32) {\n        require(x <= type(uint32).max);\n        return uint32(x);\n    }\n\n    function Uint112(uint256 x) internal pure returns (uint112) {\n        require(x <= type(uint112).max);\n        return uint112(x);\n    }\n\n    function Uint96(uint256 x) internal pure returns (uint96) {\n        require(x <= type(uint96).max);\n        return uint96(x);\n    }\n\n    function Uint128(uint256 x) internal pure returns (uint128) {\n        require(x <= type(uint128).max);\n        return uint128(x);\n    }\n\n    function isAApproxB(\n        uint256 a,\n        uint256 b,\n        uint256 eps\n    ) internal pure returns (bool) {\n        return mulDown(b, ONE - eps) <= a && a <= mulDown(b, ONE + eps);\n    }\n\n    function isAGreaterApproxB(\n        uint256 a,\n        uint256 b,\n        uint256 eps\n    ) internal pure returns (bool) {\n        return a >= b && a <= mulDown(b, ONE + eps);\n    }\n\n    function isASmallerApproxB(\n        uint256 a,\n        uint256 b,\n        uint256 eps\n    ) internal pure returns (bool) {\n        return a <= b && a >= mulDown(b, ONE - eps);\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/libraries/MiniHelpers.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nlibrary MiniHelpers {\n    function isCurrentlyExpired(uint256 expiry) internal view returns (bool) {\n        return (expiry <= block.timestamp);\n    }\n\n    function isExpired(uint256 expiry, uint256 blockTime) internal pure returns (bool) {\n        return (expiry <= blockTime);\n    }\n\n    function isTimeInThePast(uint256 timestamp) internal view returns (bool) {\n        return (timestamp <= block.timestamp); // same definition as isCurrentlyExpired\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/Market/MarketMathCore.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport \"../libraries/math/PMath.sol\";\nimport \"../libraries/math/LogExpMath.sol\";\n\nimport \"../StandardizedYield/PYIndex.sol\";\nimport \"../libraries/MiniHelpers.sol\";\nimport \"../libraries/Errors.sol\";\n\nstruct MarketState {\n    int256 totalPt;\n    int256 totalSy;\n    int256 totalLp;\n    address treasury;\n    /// immutable variables ///\n    int256 scalarRoot;\n    uint256 expiry;\n    /// fee data ///\n    uint256 lnFeeRateRoot;\n    uint256 reserveFeePercent; // base 100\n    /// last trade data ///\n    uint256 lastLnImpliedRate;\n}\n\n// params that are expensive to compute, therefore we pre-compute them\nstruct MarketPreCompute {\n    int256 rateScalar;\n    int256 totalAsset;\n    int256 rateAnchor;\n    int256 feeRate;\n}\n\n// solhint-disable ordering\nlibrary MarketMathCore {\n    using PMath for uint256;\n    using PMath for int256;\n    using LogExpMath for int256;\n    using PYIndexLib for PYIndex;\n\n    int256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;\n    int256 internal constant PERCENTAGE_DECIMALS = 100;\n    uint256 internal constant DAY = 86400;\n    uint256 internal constant IMPLIED_RATE_TIME = 365 * DAY;\n\n    int256 internal constant MAX_MARKET_PROPORTION = (1e18 * 96) / 100;\n\n    using PMath for uint256;\n    using PMath for int256;\n\n    /*///////////////////////////////////////////////////////////////\n                UINT FUNCTIONS TO PROXY TO CORE FUNCTIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function addLiquidity(\n        MarketState memory market,\n        uint256 syDesired,\n        uint256 ptDesired,\n        uint256 blockTime\n    )\n        internal\n        pure\n        returns (uint256 lpToReserve, uint256 lpToAccount, uint256 syUsed, uint256 ptUsed)\n    {\n        (\n            int256 _lpToReserve,\n            int256 _lpToAccount,\n            int256 _syUsed,\n            int256 _ptUsed\n        ) = addLiquidityCore(market, syDesired.Int(), ptDesired.Int(), blockTime);\n\n        lpToReserve = _lpToReserve.Uint();\n        lpToAccount = _lpToAccount.Uint();\n        syUsed = _syUsed.Uint();\n        ptUsed = _ptUsed.Uint();\n    }\n\n    function removeLiquidity(\n        MarketState memory market,\n        uint256 lpToRemove\n    ) internal pure returns (uint256 netSyToAccount, uint256 netPtToAccount) {\n        (int256 _syToAccount, int256 _ptToAccount) = removeLiquidityCore(market, lpToRemove.Int());\n\n        netSyToAccount = _syToAccount.Uint();\n        netPtToAccount = _ptToAccount.Uint();\n    }\n\n    function swapExactPtForSy(\n        MarketState memory market,\n        PYIndex index,\n        uint256 exactPtToMarket,\n        uint256 blockTime\n    ) internal pure returns (uint256 netSyToAccount, uint256 netSyFee, uint256 netSyToReserve) {\n        (int256 _netSyToAccount, int256 _netSyFee, int256 _netSyToReserve) = executeTradeCore(\n            market,\n            index,\n            exactPtToMarket.neg(),\n            blockTime\n        );\n\n        netSyToAccount = _netSyToAccount.Uint();\n        netSyFee = _netSyFee.Uint();\n        netSyToReserve = _netSyToReserve.Uint();\n    }\n\n    function swapSyForExactPt(\n        MarketState memory market,\n        PYIndex index,\n        uint256 exactPtToAccount,\n        uint256 blockTime\n    ) internal pure returns (uint256 netSyToMarket, uint256 netSyFee, uint256 netSyToReserve) {\n        (int256 _netSyToAccount, int256 _netSyFee, int256 _netSyToReserve) = executeTradeCore(\n            market,\n            index,\n            exactPtToAccount.Int(),\n            blockTime\n        );\n\n        netSyToMarket = _netSyToAccount.neg().Uint();\n        netSyFee = _netSyFee.Uint();\n        netSyToReserve = _netSyToReserve.Uint();\n    }\n\n    /*///////////////////////////////////////////////////////////////\n                    CORE FUNCTIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function addLiquidityCore(\n        MarketState memory market,\n        int256 syDesired,\n        int256 ptDesired,\n        uint256 blockTime\n    )\n        internal\n        pure\n        returns (int256 lpToReserve, int256 lpToAccount, int256 syUsed, int256 ptUsed)\n    {\n        /// ------------------------------------------------------------\n        /// CHECKS\n        /// ------------------------------------------------------------\n        if (syDesired == 0 || ptDesired == 0) revert Errors.MarketZeroAmountsInput();\n        if (MiniHelpers.isExpired(market.expiry, blockTime)) revert Errors.MarketExpired();\n\n        /// ------------------------------------------------------------\n        /// MATH\n        /// ------------------------------------------------------------\n        if (market.totalLp == 0) {\n            lpToAccount = PMath.sqrt((syDesired * ptDesired).Uint()).Int() - MINIMUM_LIQUIDITY;\n            lpToReserve = MINIMUM_LIQUIDITY;\n            syUsed = syDesired;\n            ptUsed = ptDesired;\n        } else {\n            int256 netLpByPt = (ptDesired * market.totalLp) / market.totalPt;\n            int256 netLpBySy = (syDesired * market.totalLp) / market.totalSy;\n            if (netLpByPt < netLpBySy) {\n                lpToAccount = netLpByPt;\n                ptUsed = ptDesired;\n                syUsed = (market.totalSy * lpToAccount) / market.totalLp;\n            } else {\n                lpToAccount = netLpBySy;\n                syUsed = syDesired;\n                ptUsed = (market.totalPt * lpToAccount) / market.totalLp;\n            }\n        }\n\n        if (lpToAccount <= 0) revert Errors.MarketZeroAmountsOutput();\n\n        /// ------------------------------------------------------------\n        /// WRITE\n        /// ------------------------------------------------------------\n        market.totalSy += syUsed;\n        market.totalPt += ptUsed;\n        market.totalLp += lpToAccount + lpToReserve;\n    }\n\n    function removeLiquidityCore(\n        MarketState memory market,\n        int256 lpToRemove\n    ) internal pure returns (int256 netSyToAccount, int256 netPtToAccount) {\n        /// ------------------------------------------------------------\n        /// CHECKS\n        /// ------------------------------------------------------------\n        if (lpToRemove == 0) revert Errors.MarketZeroAmountsInput();\n\n        /// ------------------------------------------------------------\n        /// MATH\n        /// ------------------------------------------------------------\n        netSyToAccount = (lpToRemove * market.totalSy) / market.totalLp;\n        netPtToAccount = (lpToRemove * market.totalPt) / market.totalLp;\n\n        if (netSyToAccount == 0 && netPtToAccount == 0) revert Errors.MarketZeroAmountsOutput();\n\n        /// ------------------------------------------------------------\n        /// WRITE\n        /// ------------------------------------------------------------\n        market.totalLp = market.totalLp.subNoNeg(lpToRemove);\n        market.totalPt = market.totalPt.subNoNeg(netPtToAccount);\n        market.totalSy = market.totalSy.subNoNeg(netSyToAccount);\n    }\n\n    function executeTradeCore(\n        MarketState memory market,\n        PYIndex index,\n        int256 netPtToAccount,\n        uint256 blockTime\n    ) internal pure returns (int256 netSyToAccount, int256 netSyFee, int256 netSyToReserve) {\n        /// ------------------------------------------------------------\n        /// CHECKS\n        /// ------------------------------------------------------------\n        if (MiniHelpers.isExpired(market.expiry, blockTime)) revert Errors.MarketExpired();\n        if (market.totalPt <= netPtToAccount)\n            revert Errors.MarketInsufficientPtForTrade(market.totalPt, netPtToAccount);\n\n        /// ------------------------------------------------------------\n        /// MATH\n        /// ------------------------------------------------------------\n        MarketPreCompute memory comp = getMarketPreCompute(market, index, blockTime);\n\n        (netSyToAccount, netSyFee, netSyToReserve) = calcTrade(\n            market,\n            comp,\n            index,\n            netPtToAccount\n        );\n\n        /// ------------------------------------------------------------\n        /// WRITE\n        /// ------------------------------------------------------------\n        _setNewMarketStateTrade(\n            market,\n            comp,\n            index,\n            netPtToAccount,\n            netSyToAccount,\n            netSyToReserve,\n            blockTime\n        );\n    }\n\n    function getMarketPreCompute(\n        MarketState memory market,\n        PYIndex index,\n        uint256 blockTime\n    ) internal pure returns (MarketPreCompute memory res) {\n        if (MiniHelpers.isExpired(market.expiry, blockTime)) revert Errors.MarketExpired();\n\n        uint256 timeToExpiry = market.expiry - blockTime;\n\n        res.rateScalar = _getRateScalar(market, timeToExpiry);\n        res.totalAsset = index.syToAsset(market.totalSy);\n\n        if (market.totalPt == 0 || res.totalAsset == 0)\n            revert Errors.MarketZeroTotalPtOrTotalAsset(market.totalPt, res.totalAsset);\n\n        res.rateAnchor = _getRateAnchor(\n            market.totalPt,\n            market.lastLnImpliedRate,\n            res.totalAsset,\n            res.rateScalar,\n            timeToExpiry\n        );\n        res.feeRate = _getExchangeRateFromImpliedRate(market.lnFeeRateRoot, timeToExpiry);\n    }\n\n    function calcTrade(\n        MarketState memory market,\n        MarketPreCompute memory comp,\n        PYIndex index,\n        int256 netPtToAccount\n    ) internal pure returns (int256 netSyToAccount, int256 netSyFee, int256 netSyToReserve) {\n        int256 preFeeExchangeRate = _getExchangeRate(\n            market.totalPt,\n            comp.totalAsset,\n            comp.rateScalar,\n            comp.rateAnchor,\n            netPtToAccount\n        );\n\n        int256 preFeeAssetToAccount = netPtToAccount.divDown(preFeeExchangeRate).neg();\n        int256 fee = comp.feeRate;\n\n        if (netPtToAccount > 0) {\n            int256 postFeeExchangeRate = preFeeExchangeRate.divDown(fee);\n            if (postFeeExchangeRate < PMath.IONE)\n                revert Errors.MarketExchangeRateBelowOne(postFeeExchangeRate);\n\n            fee = preFeeAssetToAccount.mulDown(PMath.IONE - fee);\n        } else {\n            fee = ((preFeeAssetToAccount * (PMath.IONE - fee)) / fee).neg();\n        }\n\n        int256 netAssetToReserve = (fee * market.reserveFeePercent.Int()) / PERCENTAGE_DECIMALS;\n        int256 netAssetToAccount = preFeeAssetToAccount - fee;\n\n        netSyToAccount = netAssetToAccount < 0\n            ? index.assetToSyUp(netAssetToAccount)\n            : index.assetToSy(netAssetToAccount);\n        netSyFee = index.assetToSy(fee);\n        netSyToReserve = index.assetToSy(netAssetToReserve);\n    }\n\n    function _setNewMarketStateTrade(\n        MarketState memory market,\n        MarketPreCompute memory comp,\n        PYIndex index,\n        int256 netPtToAccount,\n        int256 netSyToAccount,\n        int256 netSyToReserve,\n        uint256 blockTime\n    ) internal pure {\n        uint256 timeToExpiry = market.expiry - blockTime;\n\n        market.totalPt = market.totalPt.subNoNeg(netPtToAccount);\n        market.totalSy = market.totalSy.subNoNeg(netSyToAccount + netSyToReserve);\n\n        market.lastLnImpliedRate = _getLnImpliedRate(\n            market.totalPt,\n            index.syToAsset(market.totalSy),\n            comp.rateScalar,\n            comp.rateAnchor,\n            timeToExpiry\n        );\n\n        if (market.lastLnImpliedRate == 0) revert Errors.MarketZeroLnImpliedRate();\n    }\n\n    function _getRateAnchor(\n        int256 totalPt,\n        uint256 lastLnImpliedRate,\n        int256 totalAsset,\n        int256 rateScalar,\n        uint256 timeToExpiry\n    ) internal pure returns (int256 rateAnchor) {\n        int256 newExchangeRate = _getExchangeRateFromImpliedRate(lastLnImpliedRate, timeToExpiry);\n\n        if (newExchangeRate < PMath.IONE) revert Errors.MarketExchangeRateBelowOne(newExchangeRate);\n\n        {\n            int256 proportion = totalPt.divDown(totalPt + totalAsset);\n\n            int256 lnProportion = _logProportion(proportion);\n\n            rateAnchor = newExchangeRate - lnProportion.divDown(rateScalar);\n        }\n    }\n\n    /// @notice Calculates the current market implied rate.\n    /// @return lnImpliedRate the implied rate\n    function _getLnImpliedRate(\n        int256 totalPt,\n        int256 totalAsset,\n        int256 rateScalar,\n        int256 rateAnchor,\n        uint256 timeToExpiry\n    ) internal pure returns (uint256 lnImpliedRate) {\n        // This will check for exchange rates < PMath.IONE\n        int256 exchangeRate = _getExchangeRate(totalPt, totalAsset, rateScalar, rateAnchor, 0);\n\n        // exchangeRate >= 1 so its ln >= 0\n        uint256 lnRate = exchangeRate.ln().Uint();\n\n        lnImpliedRate = (lnRate * IMPLIED_RATE_TIME) / timeToExpiry;\n    }\n\n    /// @notice Converts an implied rate to an exchange rate given a time to expiry. The\n    /// formula is E = e^rt\n    function _getExchangeRateFromImpliedRate(\n        uint256 lnImpliedRate,\n        uint256 timeToExpiry\n    ) internal pure returns (int256 exchangeRate) {\n        uint256 rt = (lnImpliedRate * timeToExpiry) / IMPLIED_RATE_TIME;\n\n        exchangeRate = LogExpMath.exp(rt.Int());\n    }\n\n    function _getExchangeRate(\n        int256 totalPt,\n        int256 totalAsset,\n        int256 rateScalar,\n        int256 rateAnchor,\n        int256 netPtToAccount\n    ) internal pure returns (int256 exchangeRate) {\n        int256 numerator = totalPt.subNoNeg(netPtToAccount);\n\n        int256 proportion = (numerator.divDown(totalPt + totalAsset));\n\n        if (proportion > MAX_MARKET_PROPORTION)\n            revert Errors.MarketProportionTooHigh(proportion, MAX_MARKET_PROPORTION);\n\n        int256 lnProportion = _logProportion(proportion);\n\n        exchangeRate = lnProportion.divDown(rateScalar) + rateAnchor;\n\n        if (exchangeRate < PMath.IONE) revert Errors.MarketExchangeRateBelowOne(exchangeRate);\n    }\n\n    function _logProportion(int256 proportion) internal pure returns (int256 res) {\n        if (proportion == PMath.IONE) revert Errors.MarketProportionMustNotEqualOne();\n\n        int256 logitP = proportion.divDown(PMath.IONE - proportion);\n\n        res = logitP.ln();\n    }\n\n    function _getRateScalar(\n        MarketState memory market,\n        uint256 timeToExpiry\n    ) internal pure returns (int256 rateScalar) {\n        rateScalar = (market.scalarRoot * IMPLIED_RATE_TIME.Int()) / timeToExpiry.Int();\n        if (rateScalar <= 0) revert Errors.MarketRateScalarBelowZero(rateScalar);\n    }\n\n    function setInitialLnImpliedRate(\n        MarketState memory market,\n        PYIndex index,\n        int256 initialAnchor,\n        uint256 blockTime\n    ) internal pure {\n        /// ------------------------------------------------------------\n        /// CHECKS\n        /// ------------------------------------------------------------\n        if (MiniHelpers.isExpired(market.expiry, blockTime)) revert Errors.MarketExpired();\n\n        /// ------------------------------------------------------------\n        /// MATH\n        /// ------------------------------------------------------------\n        int256 totalAsset = index.syToAsset(market.totalSy);\n        uint256 timeToExpiry = market.expiry - blockTime;\n        int256 rateScalar = _getRateScalar(market, timeToExpiry);\n\n        /// ------------------------------------------------------------\n        /// WRITE\n        /// ------------------------------------------------------------\n        market.lastLnImpliedRate = _getLnImpliedRate(\n            market.totalPt,\n            totalAsset,\n            rateScalar,\n            initialAnchor,\n            timeToExpiry\n        );\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/StandardizedYield/PYIndex.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\nimport \"../../interfaces/IPYieldToken.sol\";\nimport \"../../interfaces/IPPrincipalToken.sol\";\n\nimport \"./SYUtils.sol\";\nimport \"../libraries/math/PMath.sol\";\n\ntype PYIndex is uint256;\n\nlibrary PYIndexLib {\n    using PMath for uint256;\n    using PMath for int256;\n\n    function newIndex(IPYieldToken YT) internal returns (PYIndex) {\n        return PYIndex.wrap(YT.pyIndexCurrent());\n    }\n\n    function syToAsset(PYIndex index, uint256 syAmount) internal pure returns (uint256) {\n        return SYUtils.syToAsset(PYIndex.unwrap(index), syAmount);\n    }\n\n    function assetToSy(PYIndex index, uint256 assetAmount) internal pure returns (uint256) {\n        return SYUtils.assetToSy(PYIndex.unwrap(index), assetAmount);\n    }\n\n    function assetToSyUp(PYIndex index, uint256 assetAmount) internal pure returns (uint256) {\n        return SYUtils.assetToSyUp(PYIndex.unwrap(index), assetAmount);\n    }\n\n    function syToAssetUp(PYIndex index, uint256 syAmount) internal pure returns (uint256) {\n        uint256 _index = PYIndex.unwrap(index);\n        return SYUtils.syToAssetUp(_index, syAmount);\n    }\n\n    function syToAsset(PYIndex index, int256 syAmount) internal pure returns (int256) {\n        int256 sign = syAmount < 0 ? int256(-1) : int256(1);\n        return sign * (SYUtils.syToAsset(PYIndex.unwrap(index), syAmount.abs())).Int();\n    }\n\n    function assetToSy(PYIndex index, int256 assetAmount) internal pure returns (int256) {\n        int256 sign = assetAmount < 0 ? int256(-1) : int256(1);\n        return sign * (SYUtils.assetToSy(PYIndex.unwrap(index), assetAmount.abs())).Int();\n    }\n\n    function assetToSyUp(PYIndex index, int256 assetAmount) internal pure returns (int256) {\n        int256 sign = assetAmount < 0 ? int256(-1) : int256(1);\n        return sign * (SYUtils.assetToSyUp(PYIndex.unwrap(index), assetAmount.abs())).Int();\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/core/StandardizedYield/SYUtils.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nlibrary SYUtils {\n    uint256 internal constant ONE = 1e18;\n\n    function syToAsset(uint256 exchangeRate, uint256 syAmount) internal pure returns (uint256) {\n        return (syAmount * exchangeRate) / ONE;\n    }\n\n    function syToAssetUp(uint256 exchangeRate, uint256 syAmount) internal pure returns (uint256) {\n        return (syAmount * exchangeRate + ONE - 1) / ONE;\n    }\n\n    function assetToSy(uint256 exchangeRate, uint256 assetAmount) internal pure returns (uint256) {\n        return (assetAmount * ONE) / exchangeRate;\n    }\n\n    function assetToSyUp(\n        uint256 exchangeRate,\n        uint256 assetAmount\n    ) internal pure returns (uint256) {\n        return (assetAmount * ONE + exchangeRate - 1) / exchangeRate;\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IPGauge.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\ninterface IPGauge {\n    function totalActiveSupply() external view returns (uint256);\n\n    function activeBalance(address user) external view returns (uint256);\n\n    // only available for newer factories. please check the verified contracts\n    event RedeemRewards(address indexed user, uint256[] rewardsOut);\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IPInterestManagerYT.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\ninterface IPInterestManagerYT {\n    function userInterest(\n        address user\n    ) external view returns (uint128 lastPYIndex, uint128 accruedInterest);\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IPMarket.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./IPPrincipalToken.sol\";\nimport \"./IPYieldToken.sol\";\nimport \"./IStandardizedYield.sol\";\nimport \"./IPGauge.sol\";\nimport \"../core/Market/MarketMathCore.sol\";\n\ninterface IPMarket is IERC20Metadata, IPGauge {\n    event Mint(\n        address indexed receiver,\n        uint256 netLpMinted,\n        uint256 netSyUsed,\n        uint256 netPtUsed\n    );\n\n    event Burn(\n        address indexed receiverSy,\n        address indexed receiverPt,\n        uint256 netLpBurned,\n        uint256 netSyOut,\n        uint256 netPtOut\n    );\n\n    event Swap(\n        address indexed caller,\n        address indexed receiver,\n        int256 netPtOut,\n        int256 netSyOut,\n        uint256 netSyFee,\n        uint256 netSyToReserve\n    );\n\n    event UpdateImpliedRate(uint256 indexed timestamp, uint256 lnLastImpliedRate);\n\n    event IncreaseObservationCardinalityNext(\n        uint16 observationCardinalityNextOld,\n        uint16 observationCardinalityNextNew\n    );\n\n    function mint(\n        address receiver,\n        uint256 netSyDesired,\n        uint256 netPtDesired\n    ) external returns (uint256 netLpOut, uint256 netSyUsed, uint256 netPtUsed);\n\n    function burn(\n        address receiverSy,\n        address receiverPt,\n        uint256 netLpToBurn\n    ) external returns (uint256 netSyOut, uint256 netPtOut);\n\n    function swapExactPtForSy(\n        address receiver,\n        uint256 exactPtIn,\n        bytes calldata data\n    ) external returns (uint256 netSyOut, uint256 netSyFee);\n\n    function swapSyForExactPt(\n        address receiver,\n        uint256 exactPtOut,\n        bytes calldata data\n    ) external returns (uint256 netSyIn, uint256 netSyFee);\n\n    function redeemRewards(address user) external returns (uint256[] memory);\n\n    function readState(address router) external view returns (MarketState memory market);\n\n    function observe(\n        uint32[] memory secondsAgos\n    ) external view returns (uint216[] memory lnImpliedRateCumulative);\n\n    function increaseObservationsCardinalityNext(uint16 cardinalityNext) external;\n\n    function readTokens()\n        external\n        view\n        returns (IStandardizedYield _SY, IPPrincipalToken _PT, IPYieldToken _YT);\n\n    function getRewardTokens() external view returns (address[] memory);\n\n    function isExpired() external view returns (bool);\n\n    function expiry() external view returns (uint256);\n\n    function observations(\n        uint256 index\n    )\n        external\n        view\n        returns (uint32 blockTimestamp, uint216 lnImpliedRateCumulative, bool initialized);\n\n    function _storage()\n        external\n        view\n        returns (\n            int128 totalPt,\n            int128 totalSy,\n            uint96 lastLnImpliedRate,\n            uint16 observationIndex,\n            uint16 observationCardinality,\n            uint16 observationCardinalityNext\n        );\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IPPrincipalToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IPPrincipalToken is IERC20Metadata {\n    function burnByYT(address user, uint256 amount) external;\n\n    function mintByYT(address user, uint256 amount) external;\n\n    function initialize(address _YT) external;\n\n    function SY() external view returns (address);\n\n    function YT() external view returns (address);\n\n    function factory() external view returns (address);\n\n    function expiry() external view returns (uint256);\n\n    function isExpired() external view returns (bool);\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IPYieldToken.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./IRewardManager.sol\";\nimport \"./IPInterestManagerYT.sol\";\n\ninterface IPYieldToken is IERC20Metadata, IRewardManager, IPInterestManagerYT {\n    event NewInterestIndex(uint256 indexed newIndex);\n\n    event Mint(\n        address indexed caller,\n        address indexed receiverPT,\n        address indexed receiverYT,\n        uint256 amountSyToMint,\n        uint256 amountPYOut\n    );\n\n    event Burn(\n        address indexed caller,\n        address indexed receiver,\n        uint256 amountPYToRedeem,\n        uint256 amountSyOut\n    );\n\n    event RedeemRewards(address indexed user, uint256[] amountRewardsOut);\n\n    event RedeemInterest(address indexed user, uint256 interestOut);\n\n    event WithdrawFeeToTreasury(uint256[] amountRewardsOut, uint256 syOut);\n\n    function mintPY(address receiverPT, address receiverYT) external returns (uint256 amountPYOut);\n\n    function redeemPY(address receiver) external returns (uint256 amountSyOut);\n\n    function redeemPYMulti(\n        address[] calldata receivers,\n        uint256[] calldata amountPYToRedeems\n    ) external returns (uint256[] memory amountSyOuts);\n\n    function redeemDueInterestAndRewards(\n        address user,\n        bool redeemInterest,\n        bool redeemRewards\n    ) external returns (uint256 interestOut, uint256[] memory rewardsOut);\n\n    function rewardIndexesCurrent() external returns (uint256[] memory);\n\n    function pyIndexCurrent() external returns (uint256);\n\n    function pyIndexStored() external view returns (uint256);\n\n    function getRewardTokens() external view returns (address[] memory);\n\n    function SY() external view returns (address);\n\n    function PT() external view returns (address);\n\n    function factory() external view returns (address);\n\n    function expiry() external view returns (uint256);\n\n    function isExpired() external view returns (bool);\n\n    function doCacheIndexSameBlock() external view returns (bool);\n\n    function pyIndexLastUpdatedBlock() external view returns (uint128);\n\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IRewardManager.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\ninterface IRewardManager {\n    function userReward(\n        address token,\n        address user\n    ) external view returns (uint128 index, uint128 accrued);\n}\n"
      },
      "@pendle/core-v2/contracts/interfaces/IStandardizedYield.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n/*\n * MIT License\n * ===========\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n */\n\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IStandardizedYield is IERC20Metadata {\n    /// @dev Emitted when any base tokens is deposited to mint shares\n    event Deposit(\n        address indexed caller,\n        address indexed receiver,\n        address indexed tokenIn,\n        uint256 amountDeposited,\n        uint256 amountSyOut\n    );\n\n    /// @dev Emitted when any shares are redeemed for base tokens\n    event Redeem(\n        address indexed caller,\n        address indexed receiver,\n        address indexed tokenOut,\n        uint256 amountSyToRedeem,\n        uint256 amountTokenOut\n    );\n\n    /// @dev check `assetInfo()` for more information\n    enum AssetType {\n        TOKEN,\n        LIQUIDITY\n    }\n\n    /// @dev Emitted when (`user`) claims their rewards\n    event ClaimRewards(address indexed user, address[] rewardTokens, uint256[] rewardAmounts);\n\n    /**\n     * @notice mints an amount of shares by depositing a base token.\n     * @param receiver shares recipient address\n     * @param tokenIn address of the base tokens to mint shares\n     * @param amountTokenToDeposit amount of base tokens to be transferred from (`msg.sender`)\n     * @param minSharesOut reverts if amount of shares minted is lower than this\n     * @return amountSharesOut amount of shares minted\n     * @dev Emits a {Deposit} event\n     *\n     * Requirements:\n     * - (`tokenIn`) must be a valid base token.\n     */\n    function deposit(\n        address receiver,\n        address tokenIn,\n        uint256 amountTokenToDeposit,\n        uint256 minSharesOut\n    ) external payable returns (uint256 amountSharesOut);\n\n    /**\n     * @notice redeems an amount of base tokens by burning some shares\n     * @param receiver recipient address\n     * @param amountSharesToRedeem amount of shares to be burned\n     * @param tokenOut address of the base token to be redeemed\n     * @param minTokenOut reverts if amount of base token redeemed is lower than this\n     * @param burnFromInternalBalance if true, burns from balance of `address(this)`, otherwise burns from `msg.sender`\n     * @return amountTokenOut amount of base tokens redeemed\n     * @dev Emits a {Redeem} event\n     *\n     * Requirements:\n     * - (`tokenOut`) must be a valid base token.\n     */\n    function redeem(\n        address receiver,\n        uint256 amountSharesToRedeem,\n        address tokenOut,\n        uint256 minTokenOut,\n        bool burnFromInternalBalance\n    ) external returns (uint256 amountTokenOut);\n\n    /**\n     * @notice exchangeRate * syBalance / 1e18 must return the asset balance of the account\n     * @notice vice-versa, if a user uses some amount of tokens equivalent to X asset, the amount of sy\n     he can mint must be X * exchangeRate / 1e18\n     * @dev SYUtils's assetToSy & syToAsset should be used instead of raw multiplication\n     & division\n     */\n    function exchangeRate() external view returns (uint256 res);\n\n    /**\n     * @notice claims reward for (`user`)\n     * @param user the user receiving their rewards\n     * @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`\n     * @dev\n     * Emits a `ClaimRewards` event\n     * See {getRewardTokens} for list of reward tokens\n     */\n    function claimRewards(address user) external returns (uint256[] memory rewardAmounts);\n\n    /**\n     * @notice get the amount of unclaimed rewards for (`user`)\n     * @param user the user to check for\n     * @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`\n     */\n    function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts);\n\n    function rewardIndexesCurrent() external returns (uint256[] memory indexes);\n\n    function rewardIndexesStored() external view returns (uint256[] memory indexes);\n\n    /**\n     * @notice returns the list of reward token addresses\n     */\n    function getRewardTokens() external view returns (address[] memory);\n\n    /**\n     * @notice returns the address of the underlying yield token\n     */\n    function yieldToken() external view returns (address);\n\n    /**\n     * @notice returns all tokens that can mint this SY\n     */\n    function getTokensIn() external view returns (address[] memory res);\n\n    /**\n     * @notice returns all tokens that can be redeemed by this SY\n     */\n    function getTokensOut() external view returns (address[] memory res);\n\n    function isValidTokenIn(address token) external view returns (bool);\n\n    function isValidTokenOut(address token) external view returns (bool);\n\n    function previewDeposit(address tokenIn, uint256 amountTokenToDeposit)\n        external\n        view\n        returns (uint256 amountSharesOut);\n\n    function previewRedeem(address tokenOut, uint256 amountSharesToRedeem)\n        external\n        view\n        returns (uint256 amountTokenOut);\n\n    /**\n     * @notice This function contains information to interpret what the asset is\n     * @return assetType the type of the asset (0 for ERC20 tokens, 1 for AMM liquidity tokens,\n        2 for bridged yield bearing tokens like wstETH, rETH on Arbi whose the underlying asset doesn't exist on the chain)\n     * @return assetAddress the address of the asset\n     * @return assetDecimals the decimals of the asset\n     */\n    function assetInfo()\n        external\n        view\n        returns (\n            AssetType assetType,\n            address assetAddress,\n            uint8 assetDecimals\n        );\n}\n"
      },
      "@pendle/core-v2/contracts/oracles/PendleLpOracleLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport \"./PendlePtOracleLib.sol\";\n\nlibrary PendleLpOracleLib {\n    using PendlePtOracleLib for IPMarket;\n    using PMath for uint256;\n    using PMath for int256;\n    using MarketMathCore for MarketState;\n\n    /**\n      * This function returns the approximated twap rate LP/asset on market, but take into account the current rate of SY\n     This is to account for special cases where underlying asset becomes insolvent and has decreasing exchangeRate\n     * @param market market to get rate from\n     * @param duration twap duration\n     */\n    function getLpToAssetRate(IPMarket market, uint32 duration) internal view returns (uint256) {\n        (uint256 syIndex, uint256 pyIndex) = PendlePtOracleLib.getSYandPYIndexCurrent(market);\n        uint256 lpToAssetRateRaw = _getLpToAssetRateRaw(market, duration, pyIndex);\n        return (lpToAssetRateRaw * syIndex) / pyIndex;\n    }\n\n    function _getLpToAssetRateRaw(\n        IPMarket market,\n        uint32 duration,\n        uint256 pyIndex\n    ) private view returns (uint256 lpToAssetRateRaw) {\n        MarketState memory state = market.readState(address(0));\n\n        MarketPreCompute memory comp = state.getMarketPreCompute(\n            PYIndex.wrap(pyIndex),\n            block.timestamp\n        );\n\n        int256 totalHypotheticalAsset;\n        if (state.expiry <= block.timestamp) {\n            // 1 PT = 1 Asset post-expiry\n            totalHypotheticalAsset = state.totalPt + comp.totalAsset;\n        } else {\n            (int256 rateOracle, int256 rateHypTrade) = _getPtRatesRaw(market, state, duration);\n            int256 cParam = LogExpMath.exp(\n                comp.rateScalar.mulDown((rateOracle - comp.rateAnchor))\n            );\n\n            int256 tradeSize = (cParam.mulDown(comp.totalAsset) - state.totalPt).divDown(\n                PMath.IONE + cParam.divDown(rateHypTrade)\n            );\n\n            totalHypotheticalAsset =\n                comp.totalAsset -\n                tradeSize.divDown(rateHypTrade) +\n                (state.totalPt + tradeSize).divDown(rateOracle);\n        }\n\n        lpToAssetRateRaw = totalHypotheticalAsset.divDown(state.totalLp).Uint();\n    }\n\n    function _getPtRatesRaw(\n        IPMarket market,\n        MarketState memory state,\n        uint32 duration\n    ) private view returns (int256 rateOracle, int256 rateHypTrade) {\n        rateOracle = PMath.IONE.divDown(market.getPtToAssetRateRaw(duration).Int());\n        int256 rateLastTrade = MarketMathCore._getExchangeRateFromImpliedRate(\n            state.lastLnImpliedRate,\n            state.expiry - block.timestamp\n        );\n        rateHypTrade = (rateLastTrade + rateOracle) / 2;\n    }\n}\n"
      },
      "@pendle/core-v2/contracts/oracles/PendlePtOracleLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport \"../interfaces/IPMarket.sol\";\nimport \"../core/libraries/math/PMath.sol\";\n\nlibrary PendlePtOracleLib {\n    using PMath for uint256;\n    using PMath for int256;\n\n    /**\n     * This function returns the twap rate PT/Asset on market, but take into account the current rate of SY\n     This is to account for special cases where underlying asset becomes insolvent and has decreasing exchangeRate\n     * @param market market to get rate from\n     * @param duration twap duration\n     */\n    function getPtToAssetRate(IPMarket market, uint32 duration) internal view returns (uint256) {\n        (uint256 syIndex, uint256 pyIndex) = getSYandPYIndexCurrent(market);\n        return (getPtToAssetRateRaw(market,duration) * syIndex) / pyIndex;\n    }\n\n    function getPtToAssetRateRaw(IPMarket market, uint32 duration) internal view returns (uint256) {\n        uint256 expiry = market.expiry();\n\n        if (expiry <= block.timestamp) {\n            return PMath.ONE;\n        } else {\n            uint256 lnImpliedRate = _getMarketLnImpliedRate(market, duration);\n            uint256 timeToExpiry = expiry - block.timestamp;\n            uint256 assetToPtRate =\n                MarketMathCore._getExchangeRateFromImpliedRate(lnImpliedRate, timeToExpiry).Uint();\n            return PMath.ONE.divDown(assetToPtRate);\n        }\n    }\n\n    function getSYandPYIndexCurrent(IPMarket market)\n        internal\n        view\n        returns (uint256 syIndex, uint256 pyIndex)\n    {\n        (IStandardizedYield SY, , IPYieldToken YT) = market.readTokens();\n\n        syIndex = SY.exchangeRate();\n        uint256 pyIndexStored = YT.pyIndexStored();\n\n        if (YT.doCacheIndexSameBlock() && YT.pyIndexLastUpdatedBlock() == block.number) {\n            pyIndex = pyIndexStored;\n        } else {\n            pyIndex = PMath.max(syIndex, pyIndexStored);\n        }\n    }\n\n    function _getMarketLnImpliedRate(IPMarket market, uint32 duration)\n        private\n        view\n        returns (uint256)\n    {\n        uint32[] memory durations = new uint32[](2);\n        durations[0] = duration;\n\n        uint216[] memory lnImpliedRateCumulative = market.observe(durations);\n        return (lnImpliedRateCumulative[1] - lnImpliedRateCumulative[0]) / duration;\n    }\n}\n"
      },
      "@rari-capital/solmate/src/utils/SSTORE2.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Read and write to persistent storage at a fraction of the cost.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SSTORE2.sol)\n/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)\nlibrary SSTORE2 {\n    uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called.\n\n    /*//////////////////////////////////////////////////////////////\n                               WRITE LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function write(bytes memory data) internal returns (address pointer) {\n        // Prefix the bytecode with a STOP opcode to ensure it cannot be called.\n        bytes memory runtimeCode = abi.encodePacked(hex\"00\", data);\n\n        bytes memory creationCode = abi.encodePacked(\n            //---------------------------------------------------------------------------------------------------------------//\n            // Opcode  | Opcode + Arguments  | Description  | Stack View                                                     //\n            //---------------------------------------------------------------------------------------------------------------//\n            // 0x60    |  0x600B             | PUSH1 11     | codeOffset                                                     //\n            // 0x59    |  0x59               | MSIZE        | 0 codeOffset                                                   //\n            // 0x81    |  0x81               | DUP2         | codeOffset 0 codeOffset                                        //\n            // 0x38    |  0x38               | CODESIZE     | codeSize codeOffset 0 codeOffset                               //\n            // 0x03    |  0x03               | SUB          | (codeSize - codeOffset) 0 codeOffset                           //\n            // 0x80    |  0x80               | DUP          | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset   //\n            // 0x92    |  0x92               | SWAP3        | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset)   //\n            // 0x59    |  0x59               | MSIZE        | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //\n            // 0x39    |  0x39               | CODECOPY     | 0 (codeSize - codeOffset)                                      //\n            // 0xf3    |  0xf3               | RETURN       |                                                                //\n            //---------------------------------------------------------------------------------------------------------------//\n            hex\"60_0B_59_81_38_03_80_92_59_39_F3\", // Returns all code in the contract except for the first 11 (0B in hex) bytes.\n            runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.\n        );\n\n        assembly {\n            // Deploy a new contract with the generated creation code.\n            // We start 32 bytes into the code to avoid copying the byte length.\n            pointer := create(0, add(creationCode, 32), mload(creationCode))\n        }\n\n        require(pointer != address(0), \"DEPLOYMENT_FAILED\");\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               READ LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function read(address pointer) internal view returns (bytes memory) {\n        return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET);\n    }\n\n    function read(address pointer, uint256 start) internal view returns (bytes memory) {\n        start += DATA_OFFSET;\n\n        return readBytecode(pointer, start, pointer.code.length - start);\n    }\n\n    function read(\n        address pointer,\n        uint256 start,\n        uint256 end\n    ) internal view returns (bytes memory) {\n        start += DATA_OFFSET;\n        end += DATA_OFFSET;\n\n        require(pointer.code.length >= end, \"OUT_OF_BOUNDS\");\n\n        return readBytecode(pointer, start, end - start);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                          INTERNAL HELPER LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function readBytecode(\n        address pointer,\n        uint256 start,\n        uint256 size\n    ) private view returns (bytes memory data) {\n        assembly {\n            // Get a pointer to some free memory.\n            data := mload(0x40)\n\n            // Update the free memory pointer to prevent overriding our data.\n            // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).\n            // Adding 31 to size and running the result through the logic above ensures\n            // the memory pointer remains word-aligned, following the Solidity convention.\n            mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))\n\n            // Store the size of the data in the first 32 byte chunk of free memory.\n            mstore(data, size)\n\n            // Copy the code into memory right after the 32 bytes we used to store the size.\n            extcodecopy(pointer, add(data, 32), start, size)\n        }\n    }\n}\n"
      },
      "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity >=0.5.0;\n\n/// @title The interface for the Uniswap V3 Factory\n/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees\ninterface IUniswapV3Factory {\n    /// @notice Emitted when the owner of the factory is changed\n    /// @param oldOwner The owner before the owner was changed\n    /// @param newOwner The owner after the owner was changed\n    event OwnerChanged(address indexed oldOwner, address indexed newOwner);\n\n    /// @notice Emitted when a pool is created\n    /// @param token0 The first token of the pool by address sort order\n    /// @param token1 The second token of the pool by address sort order\n    /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip\n    /// @param tickSpacing The minimum number of ticks between initialized ticks\n    /// @param pool The address of the created pool\n    event PoolCreated(\n        address indexed token0,\n        address indexed token1,\n        uint24 indexed fee,\n        int24 tickSpacing,\n        address pool\n    );\n\n    /// @notice Emitted when a new fee amount is enabled for pool creation via the factory\n    /// @param fee The enabled fee, denominated in hundredths of a bip\n    /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee\n    event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);\n\n    /// @notice Returns the current owner of the factory\n    /// @dev Can be changed by the current owner via setOwner\n    /// @return The address of the factory owner\n    function owner() external view returns (address);\n\n    /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled\n    /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context\n    /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee\n    /// @return The tick spacing\n    function feeAmountTickSpacing(uint24 fee) external view returns (int24);\n\n    /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist\n    /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order\n    /// @param tokenA The contract address of either token0 or token1\n    /// @param tokenB The contract address of the other token\n    /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip\n    /// @return pool The pool address\n    function getPool(\n        address tokenA,\n        address tokenB,\n        uint24 fee\n    ) external view returns (address pool);\n\n    /// @notice Creates a pool for the given two tokens and fee\n    /// @param tokenA One of the two tokens in the desired pool\n    /// @param tokenB The other of the two tokens in the desired pool\n    /// @param fee The desired fee for the pool\n    /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved\n    /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments\n    /// are invalid.\n    /// @return pool The address of the newly created pool\n    function createPool(\n        address tokenA,\n        address tokenB,\n        uint24 fee\n    ) external returns (address pool);\n\n    /// @notice Updates the owner of the factory\n    /// @dev Must be called by the current owner\n    /// @param _owner The new owner of the factory\n    function setOwner(address _owner) external;\n\n    /// @notice Enables a fee amount with the given tickSpacing\n    /// @dev Fee amounts may never be removed once enabled\n    /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)\n    /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount\n    function enableFeeAmount(uint24 fee, int24 tickSpacing) external;\n}\n"
      },
      "contracts/src/interfaces/Aave/V3/IFlashLoanReceiver.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\n/**\n * @title IFlashLoanReceiver interface\n * @notice Interface for the IFlashLoanReceiver.\n * @author Sturdy\n * @dev implement this interface to develop a flashloan-compatible flashLoanReceiver contract\n **/\ninterface IFlashLoanReceiver {\n  function executeOperation(\n    address[] calldata assets,\n    uint256[] calldata amounts,\n    uint256[] calldata premiums,\n    address initiator,\n    bytes calldata params\n  ) external returns (bool);\n}\n"
      },
      "contracts/src/interfaces/Aave/V3/IPool.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IPoolAddressesProvider} from \"./IPoolAddressesProvider.sol\";\nimport {DataTypesV3} from \"../../../libraries/Aave/DataTypesV3.sol\";\n\n/**\n * @title IPool\n * @author Aave\n * @notice Defines the basic interface for an Aave Pool.\n **/\ninterface IPool {\n    /**\n     * @dev Emitted on mintUnbacked()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address initiating the supply\n     * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens\n     * @param amount The amount of supplied assets\n     * @param referralCode The referral code used\n     **/\n    event MintUnbacked(\n        address indexed reserve,\n        address user,\n        address indexed onBehalfOf,\n        uint256 amount,\n        uint16 indexed referralCode\n    );\n\n    /**\n     * @dev Emitted on backUnbacked()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param backer The address paying for the backing\n     * @param amount The amount added as backing\n     * @param fee The amount paid in fees\n     **/\n    event BackUnbacked(\n        address indexed reserve,\n        address indexed backer,\n        uint256 amount,\n        uint256 fee\n    );\n\n    /**\n     * @dev Emitted on supply()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address initiating the supply\n     * @param onBehalfOf The beneficiary of the supply, receiving the aTokens\n     * @param amount The amount supplied\n     * @param referralCode The referral code used\n     **/\n    event Supply(\n        address indexed reserve,\n        address user,\n        address indexed onBehalfOf,\n        uint256 amount,\n        uint16 indexed referralCode\n    );\n\n    /**\n     * @dev Emitted on withdraw()\n     * @param reserve The address of the underlying asset being withdrawn\n     * @param user The address initiating the withdrawal, owner of aTokens\n     * @param to The address that will receive the underlying\n     * @param amount The amount to be withdrawn\n     **/\n    event Withdraw(\n        address indexed reserve,\n        address indexed user,\n        address indexed to,\n        uint256 amount\n    );\n\n    /**\n     * @dev Emitted on borrow() and flashLoan() when debt needs to be opened\n     * @param reserve The address of the underlying asset being borrowed\n     * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just\n     * initiator of the transaction on flashLoan()\n     * @param onBehalfOf The address that will be getting the debt\n     * @param amount The amount borrowed out\n     * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable\n     * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray\n     * @param referralCode The referral code used\n     **/\n    event Borrow(\n        address indexed reserve,\n        address user,\n        address indexed onBehalfOf,\n        uint256 amount,\n        DataTypesV3.InterestRateMode interestRateMode,\n        uint256 borrowRate,\n        uint16 indexed referralCode\n    );\n\n    /**\n     * @dev Emitted on repay()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The beneficiary of the repayment, getting his debt reduced\n     * @param repayer The address of the user initiating the repay(), providing the funds\n     * @param amount The amount repaid\n     * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly\n     **/\n    event Repay(\n        address indexed reserve,\n        address indexed user,\n        address indexed repayer,\n        uint256 amount,\n        bool useATokens\n    );\n\n    /**\n     * @dev Emitted on swapBorrowRateMode()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address of the user swapping his rate mode\n     * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable\n     **/\n    event SwapBorrowRateMode(\n        address indexed reserve,\n        address indexed user,\n        DataTypesV3.InterestRateMode interestRateMode\n    );\n\n    /**\n     * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets\n     * @param asset The address of the underlying asset of the reserve\n     * @param totalDebt The total isolation mode debt for the reserve\n     */\n    event IsolationModeTotalDebtUpdated(\n        address indexed asset,\n        uint256 totalDebt\n    );\n\n    /**\n     * @dev Emitted when the user selects a certain asset category for eMode\n     * @param user The address of the user\n     * @param categoryId The category id\n     **/\n    event UserEModeSet(address indexed user, uint8 categoryId);\n\n    /**\n     * @dev Emitted on setUserUseReserveAsCollateral()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address of the user enabling the usage as collateral\n     **/\n    event ReserveUsedAsCollateralEnabled(\n        address indexed reserve,\n        address indexed user\n    );\n\n    /**\n     * @dev Emitted on setUserUseReserveAsCollateral()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address of the user enabling the usage as collateral\n     **/\n    event ReserveUsedAsCollateralDisabled(\n        address indexed reserve,\n        address indexed user\n    );\n\n    /**\n     * @dev Emitted on rebalanceStableBorrowRate()\n     * @param reserve The address of the underlying asset of the reserve\n     * @param user The address of the user for which the rebalance has been executed\n     **/\n    event RebalanceStableBorrowRate(\n        address indexed reserve,\n        address indexed user\n    );\n\n    /**\n     * @dev Emitted on flashLoan()\n     * @param target The address of the flash loan receiver contract\n     * @param initiator The address initiating the flash loan\n     * @param asset The address of the asset being flash borrowed\n     * @param amount The amount flash borrowed\n     * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt\n     * @param premium The fee flash borrowed\n     * @param referralCode The referral code used\n     **/\n    event FlashLoan(\n        address indexed target,\n        address initiator,\n        address indexed asset,\n        uint256 amount,\n        DataTypesV3.InterestRateMode interestRateMode,\n        uint256 premium,\n        uint16 indexed referralCode\n    );\n\n    /**\n     * @dev Emitted when a borrower is liquidated.\n     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation\n     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation\n     * @param user The address of the borrower getting liquidated\n     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover\n     * @param liquidatedCollateralAmount The amount of collateral received by the liquidator\n     * @param liquidator The address of the liquidator\n     * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants\n     * to receive the underlying collateral asset directly\n     **/\n    event LiquidationCall(\n        address indexed collateralAsset,\n        address indexed debtAsset,\n        address indexed user,\n        uint256 debtToCover,\n        uint256 liquidatedCollateralAmount,\n        address liquidator,\n        bool receiveAToken\n    );\n\n    /**\n     * @dev Emitted when the state of a reserve is updated.\n     * @param reserve The address of the underlying asset of the reserve\n     * @param liquidityRate The next liquidity rate\n     * @param stableBorrowRate The next stable borrow rate\n     * @param variableBorrowRate The next variable borrow rate\n     * @param liquidityIndex The next liquidity index\n     * @param variableBorrowIndex The next variable borrow index\n     **/\n    event ReserveDataUpdated(\n        address indexed reserve,\n        uint256 liquidityRate,\n        uint256 stableBorrowRate,\n        uint256 variableBorrowRate,\n        uint256 liquidityIndex,\n        uint256 variableBorrowIndex\n    );\n\n    /**\n     * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.\n     * @param reserve The address of the reserve\n     * @param amountMinted The amount minted to the treasury\n     **/\n    event MintedToTreasury(address indexed reserve, uint256 amountMinted);\n\n    /**\n     * @dev Mints an `amount` of aTokens to the `onBehalfOf`\n     * @param asset The address of the underlying asset to mint\n     * @param amount The amount to mint\n     * @param onBehalfOf The address that will receive the aTokens\n     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     **/\n    function mintUnbacked(\n        address asset,\n        uint256 amount,\n        address onBehalfOf,\n        uint16 referralCode\n    ) external;\n\n    /**\n     * @dev Back the current unbacked underlying with `amount` and pay `fee`.\n     * @param asset The address of the underlying asset to back\n     * @param amount The amount to back\n     * @param fee The amount paid in fees\n     **/\n    function backUnbacked(address asset, uint256 amount, uint256 fee) external;\n\n    /**\n     * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n     * - E.g. User supplies 100 USDC and gets in return 100 aUSDC\n     * @param asset The address of the underlying asset to supply\n     * @param amount The amount to be supplied\n     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n     *   is a different wallet\n     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     **/\n    function supply(\n        address asset,\n        uint256 amount,\n        address onBehalfOf,\n        uint16 referralCode\n    ) external;\n\n    /**\n     * @notice Supply with transfer approval of asset to be supplied done via permit function\n     * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713\n     * @param asset The address of the underlying asset to supply\n     * @param amount The amount to be supplied\n     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n     *   is a different wallet\n     * @param deadline The deadline timestamp that the permit is valid\n     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     * @param permitV The V parameter of ERC712 permit sig\n     * @param permitR The R parameter of ERC712 permit sig\n     * @param permitS The S parameter of ERC712 permit sig\n     **/\n    function supplyWithPermit(\n        address asset,\n        uint256 amount,\n        address onBehalfOf,\n        uint16 referralCode,\n        uint256 deadline,\n        uint8 permitV,\n        bytes32 permitR,\n        bytes32 permitS\n    ) external;\n\n    /**\n     * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned\n     * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC\n     * @param asset The address of the underlying asset to withdraw\n     * @param amount The underlying amount to be withdrawn\n     *   - Send the value type(uint256).max in order to withdraw the whole aToken balance\n     * @param to The address that will receive the underlying, same as msg.sender if the user\n     *   wants to receive it on his own wallet, or a different address if the beneficiary is a\n     *   different wallet\n     * @return The final amount withdrawn\n     **/\n    function withdraw(\n        address asset,\n        uint256 amount,\n        address to\n    ) external returns (uint256);\n\n    /**\n     * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower\n     * already supplied enough collateral, or he was given enough allowance by a credit delegator on the\n     * corresponding debt token (StableDebtToken or VariableDebtToken)\n     * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet\n     *   and 100 stable/variable debt tokens, depending on the `interestRateMode`\n     * @param asset The address of the underlying asset to borrow\n     * @param amount The amount to be borrowed\n     * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable\n     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself\n     * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator\n     * if he has been given credit delegation allowance\n     **/\n    function borrow(\n        address asset,\n        uint256 amount,\n        uint256 interestRateMode,\n        uint16 referralCode,\n        address onBehalfOf\n    ) external;\n\n    /**\n     * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned\n     * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address\n     * @param asset The address of the borrowed underlying asset previously borrowed\n     * @param amount The amount to repay\n     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n     * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the\n     * user calling the function if he wants to reduce/remove his own debt, or the address of any other\n     * other borrower whose debt should be removed\n     * @return The final amount repaid\n     **/\n    function repay(\n        address asset,\n        uint256 amount,\n        uint256 interestRateMode,\n        address onBehalfOf\n    ) external returns (uint256);\n\n    /**\n     * @notice Repay with transfer approval of asset to be repaid done via permit function\n     * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713\n     * @param asset The address of the borrowed underlying asset previously borrowed\n     * @param amount The amount to repay\n     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n     * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the\n     * user calling the function if he wants to reduce/remove his own debt, or the address of any other\n     * other borrower whose debt should be removed\n     * @param deadline The deadline timestamp that the permit is valid\n     * @param permitV The V parameter of ERC712 permit sig\n     * @param permitR The R parameter of ERC712 permit sig\n     * @param permitS The S parameter of ERC712 permit sig\n     * @return The final amount repaid\n     **/\n    function repayWithPermit(\n        address asset,\n        uint256 amount,\n        uint256 interestRateMode,\n        address onBehalfOf,\n        uint256 deadline,\n        uint8 permitV,\n        bytes32 permitR,\n        bytes32 permitS\n    ) external returns (uint256);\n\n    /**\n     * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the\n     * equivalent debt tokens\n     * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens\n     * @dev  Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken\n     * balance is not enough to cover the whole debt\n     * @param asset The address of the borrowed underlying asset previously borrowed\n     * @param amount The amount to repay\n     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`\n     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable\n     * @return The final amount repaid\n     **/\n    function repayWithATokens(\n        address asset,\n        uint256 amount,\n        uint256 interestRateMode\n    ) external returns (uint256);\n\n    /**\n     * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa\n     * @param asset The address of the underlying asset borrowed\n     * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable\n     **/\n    function swapBorrowRateMode(\n        address asset,\n        uint256 interestRateMode\n    ) external;\n\n    /**\n     * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.\n     * - Users can be rebalanced if the following conditions are satisfied:\n     *     1. Usage ratio is above 95%\n     *     2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too\n     *        much has been borrowed at a stable rate and suppliers are not earning enough\n     * @param asset The address of the underlying asset borrowed\n     * @param user The address of the user to be rebalanced\n     **/\n    function rebalanceStableBorrowRate(address asset, address user) external;\n\n    /**\n     * @notice Allows suppliers to enable/disable a specific supplied asset as collateral\n     * @param asset The address of the underlying asset supplied\n     * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise\n     **/\n    function setUserUseReserveAsCollateral(\n        address asset,\n        bool useAsCollateral\n    ) external;\n\n    /**\n     * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1\n     * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives\n     *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk\n     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation\n     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation\n     * @param user The address of the borrower getting liquidated\n     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover\n     * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants\n     * to receive the underlying collateral asset directly\n     **/\n    function liquidationCall(\n        address collateralAsset,\n        address debtAsset,\n        address user,\n        uint256 debtToCover,\n        bool receiveAToken\n    ) external;\n\n    /**\n     * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,\n     * as long as the amount taken plus a fee is returned.\n     * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept\n     * into consideration. For further details please visit https://developers.aave.com\n     * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface\n     * @param assets The addresses of the assets being flash-borrowed\n     * @param amounts The amounts of the assets being flash-borrowed\n     * @param interestRateModes Types of the debt to open if the flash loan is not returned:\n     *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver\n     *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address\n     *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address\n     * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2\n     * @param params Variadic packed params to pass to the receiver as extra information\n     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     **/\n    function flashLoan(\n        address receiverAddress,\n        address[] calldata assets,\n        uint256[] calldata amounts,\n        uint256[] calldata interestRateModes,\n        address onBehalfOf,\n        bytes calldata params,\n        uint16 referralCode\n    ) external;\n\n    /**\n     * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,\n     * as long as the amount taken plus a fee is returned.\n     * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept\n     * into consideration. For further details please visit https://developers.aave.com\n     * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface\n     * @param asset The address of the asset being flash-borrowed\n     * @param amount The amount of the asset being flash-borrowed\n     * @param params Variadic packed params to pass to the receiver as extra information\n     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     **/\n    function flashLoanSimple(\n        address receiverAddress,\n        address asset,\n        uint256 amount,\n        bytes calldata params,\n        uint16 referralCode\n    ) external;\n\n    /**\n     * @notice Returns the user account data across all the reserves\n     * @param user The address of the user\n     * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed\n     * @return totalDebtBase The total debt of the user in the base currency used by the price feed\n     * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed\n     * @return currentLiquidationThreshold The liquidation threshold of the user\n     * @return ltv The loan to value of The user\n     * @return healthFactor The current health factor of the user\n     **/\n    function getUserAccountData(\n        address user\n    )\n        external\n        view\n        returns (\n            uint256 totalCollateralBase,\n            uint256 totalDebtBase,\n            uint256 availableBorrowsBase,\n            uint256 currentLiquidationThreshold,\n            uint256 ltv,\n            uint256 healthFactor\n        );\n\n    /**\n     * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an\n     * interest rate strategy\n     * @dev Only callable by the PoolConfigurator contract\n     * @param asset The address of the underlying asset of the reserve\n     * @param aTokenAddress The address of the aToken that will be assigned to the reserve\n     * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve\n     * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve\n     * @param interestRateStrategyAddress The address of the interest rate strategy contract\n     **/\n    function initReserve(\n        address asset,\n        address aTokenAddress,\n        address stableDebtAddress,\n        address variableDebtAddress,\n        address interestRateStrategyAddress\n    ) external;\n\n    /**\n     * @notice Drop a reserve\n     * @dev Only callable by the PoolConfigurator contract\n     * @param asset The address of the underlying asset of the reserve\n     **/\n    function dropReserve(address asset) external;\n\n    /**\n     * @notice Updates the address of the interest rate strategy contract\n     * @dev Only callable by the PoolConfigurator contract\n     * @param asset The address of the underlying asset of the reserve\n     * @param rateStrategyAddress The address of the interest rate strategy contract\n     **/\n    function setReserveInterestRateStrategyAddress(\n        address asset,\n        address rateStrategyAddress\n    ) external;\n\n    /**\n     * @notice Sets the configuration bitmap of the reserve as a whole\n     * @dev Only callable by the PoolConfigurator contract\n     * @param asset The address of the underlying asset of the reserve\n     * @param configuration The new configuration bitmap\n     **/\n    function setConfiguration(\n        address asset,\n        DataTypesV3.ReserveConfigurationMap calldata configuration\n    ) external;\n\n    /**\n     * @notice Returns the configuration of the reserve\n     * @param asset The address of the underlying asset of the reserve\n     * @return The configuration of the reserve\n     **/\n    function getConfiguration(\n        address asset\n    ) external view returns (DataTypesV3.ReserveConfigurationMap memory);\n\n    /**\n     * @notice Returns the configuration of the user across all the reserves\n     * @param user The user address\n     * @return The configuration of the user\n     **/\n    function getUserConfiguration(\n        address user\n    ) external view returns (DataTypesV3.UserConfigurationMap memory);\n\n    /**\n     * @notice Returns the normalized income normalized income of the reserve\n     * @param asset The address of the underlying asset of the reserve\n     * @return The reserve's normalized income\n     */\n    function getReserveNormalizedIncome(\n        address asset\n    ) external view returns (uint256);\n\n    /**\n     * @notice Returns the normalized variable debt per unit of asset\n     * @param asset The address of the underlying asset of the reserve\n     * @return The reserve normalized variable debt\n     */\n    function getReserveNormalizedVariableDebt(\n        address asset\n    ) external view returns (uint256);\n\n    /**\n     * @notice Returns the state and configuration of the reserve\n     * @param asset The address of the underlying asset of the reserve\n     * @return The state and configuration data of the reserve\n     **/\n    function getReserveData(\n        address asset\n    ) external view returns (DataTypesV3.ReserveData memory);\n\n    /**\n     * @notice Validates and finalizes an aToken transfer\n     * @dev Only callable by the overlying aToken of the `asset`\n     * @param asset The address of the underlying asset of the aToken\n     * @param from The user from which the aTokens are transferred\n     * @param to The user receiving the aTokens\n     * @param amount The amount being transferred/withdrawn\n     * @param balanceFromBefore The aToken balance of the `from` user before the transfer\n     * @param balanceToBefore The aToken balance of the `to` user before the transfer\n     */\n    function finalizeTransfer(\n        address asset,\n        address from,\n        address to,\n        uint256 amount,\n        uint256 balanceFromBefore,\n        uint256 balanceToBefore\n    ) external;\n\n    /**\n     * @notice Returns the list of the underlying assets of all the initialized reserves\n     * @dev It does not include dropped reserves\n     * @return The addresses of the underlying assets of the initialized reserves\n     **/\n    function getReservesList() external view returns (address[] memory);\n\n    /**\n     * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypesV3.ReserveData struct\n     * @param id The id of the reserve as stored in the DataTypesV3.ReserveData struct\n     * @return The address of the reserve associated with id\n     **/\n    function getReserveAddressById(uint16 id) external view returns (address);\n\n    /**\n     * @notice Returns the PoolAddressesProvider connected to this contract\n     * @return The address of the PoolAddressesProvider\n     **/\n    function ADDRESSES_PROVIDER()\n        external\n        view\n        returns (IPoolAddressesProvider);\n\n    /**\n     * @notice Updates the protocol fee on the bridging\n     * @param bridgeProtocolFee The part of the premium sent to the protocol treasury\n     */\n    function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;\n\n    /**\n     * @notice Updates flash loan premiums. Flash loan premium consists of two parts:\n     * - A part is sent to aToken holders as extra, one time accumulated interest\n     * - A part is collected by the protocol treasury\n     * @dev The total premium is calculated on the total borrowed amount\n     * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`\n     * @dev Only callable by the PoolConfigurator contract\n     * @param flashLoanPremiumTotal The total premium, expressed in bps\n     * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps\n     */\n    function updateFlashloanPremiums(\n        uint128 flashLoanPremiumTotal,\n        uint128 flashLoanPremiumToProtocol\n    ) external;\n\n    /**\n     * @notice Configures a new category for the eMode.\n     * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.\n     * The category 0 is reserved as it's the default for volatile assets\n     * @param id The id of the category\n     * @param config The configuration of the category\n     */\n    function configureEModeCategory(\n        uint8 id,\n        DataTypesV3.EModeCategory memory config\n    ) external;\n\n    /**\n     * @notice Returns the data of an eMode category\n     * @param id The id of the category\n     * @return The configuration data of the category\n     */\n    function getEModeCategoryData(\n        uint8 id\n    ) external view returns (DataTypesV3.EModeCategory memory);\n\n    /**\n     * @notice Allows a user to use the protocol in eMode\n     * @param categoryId The id of the category\n     */\n    function setUserEMode(uint8 categoryId) external;\n\n    /**\n     * @notice Returns the eMode the user is using\n     * @param user The address of the user\n     * @return The eMode id\n     */\n    function getUserEMode(address user) external view returns (uint256);\n\n    /**\n     * @notice Resets the isolation mode total debt of the given asset to zero\n     * @dev It requires the given asset has zero debt ceiling\n     * @param asset The address of the underlying asset to reset the isolationModeTotalDebt\n     */\n    function resetIsolationModeTotalDebt(address asset) external;\n\n    /**\n     * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate\n     * @return The percentage of available liquidity to borrow, expressed in bps\n     */\n    function MAX_STABLE_RATE_BORROW_SIZE_PERCENT()\n        external\n        view\n        returns (uint256);\n\n    /**\n     * @notice Returns the total fee on flash loans\n     * @return The total fee on flashloans\n     */\n    function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);\n\n    /**\n     * @notice Returns the part of the bridge fees sent to protocol\n     * @return The bridge fee sent to the protocol treasury\n     */\n    function BRIDGE_PROTOCOL_FEE() external view returns (uint256);\n\n    /**\n     * @notice Returns the part of the flashloan fees sent to protocol\n     * @return The flashloan fee sent to the protocol treasury\n     */\n    function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);\n\n    /**\n     * @notice Returns the maximum number of reserves supported to be listed in this Pool\n     * @return The maximum number of reserves supported\n     */\n    function MAX_NUMBER_RESERVES() external view returns (uint16);\n\n    /**\n     * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens\n     * @param assets The list of reserves for which the minting needs to be executed\n     **/\n    function mintToTreasury(address[] calldata assets) external;\n\n    /**\n     * @notice Rescue and transfer tokens locked in this contract\n     * @param token The address of the token\n     * @param to The address of the recipient\n     * @param amount The amount of token to transfer\n     */\n    function rescueTokens(address token, address to, uint256 amount) external;\n\n    /**\n     * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.\n     * - E.g. User supplies 100 USDC and gets in return 100 aUSDC\n     * @dev Deprecated: Use the `supply` function instead\n     * @param asset The address of the underlying asset to supply\n     * @param amount The amount to be supplied\n     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user\n     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens\n     *   is a different wallet\n     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.\n     *   0 if the action is executed directly by the user, without any middle-man\n     **/\n    function deposit(\n        address asset,\n        uint256 amount,\n        address onBehalfOf,\n        uint16 referralCode\n    ) external;\n}\n"
      },
      "contracts/src/interfaces/Aave/V3/IPoolAddressesProvider.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\n/**\n * @title IPoolAddressesProvider\n * @author Aave\n * @notice Defines the basic interface for a Pool Addresses Provider.\n **/\ninterface IPoolAddressesProvider {\n    /**\n     * @dev Emitted when the market identifier is updated.\n     * @param oldMarketId The old id of the market\n     * @param newMarketId The new id of the market\n     */\n    event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);\n\n    /**\n     * @dev Emitted when the pool is updated.\n     * @param oldAddress The old address of the Pool\n     * @param newAddress The new address of the Pool\n     */\n    event PoolUpdated(address indexed oldAddress, address indexed newAddress);\n\n    /**\n     * @dev Emitted when the pool configurator is updated.\n     * @param oldAddress The old address of the PoolConfigurator\n     * @param newAddress The new address of the PoolConfigurator\n     */\n    event PoolConfiguratorUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the price oracle is updated.\n     * @param oldAddress The old address of the PriceOracle\n     * @param newAddress The new address of the PriceOracle\n     */\n    event PriceOracleUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the ACL manager is updated.\n     * @param oldAddress The old address of the ACLManager\n     * @param newAddress The new address of the ACLManager\n     */\n    event ACLManagerUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the ACL admin is updated.\n     * @param oldAddress The old address of the ACLAdmin\n     * @param newAddress The new address of the ACLAdmin\n     */\n    event ACLAdminUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the price oracle sentinel is updated.\n     * @param oldAddress The old address of the PriceOracleSentinel\n     * @param newAddress The new address of the PriceOracleSentinel\n     */\n    event PriceOracleSentinelUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the pool data provider is updated.\n     * @param oldAddress The old address of the PoolDataProvider\n     * @param newAddress The new address of the PoolDataProvider\n     */\n    event PoolDataProviderUpdated(\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when a new proxy is created.\n     * @param id The identifier of the proxy\n     * @param proxyAddress The address of the created proxy contract\n     * @param implementationAddress The address of the implementation contract\n     */\n    event ProxyCreated(\n        bytes32 indexed id,\n        address indexed proxyAddress,\n        address indexed implementationAddress\n    );\n\n    /**\n     * @dev Emitted when a new non-proxied contract address is registered.\n     * @param id The identifier of the contract\n     * @param oldAddress The address of the old contract\n     * @param newAddress The address of the new contract\n     */\n    event AddressSet(\n        bytes32 indexed id,\n        address indexed oldAddress,\n        address indexed newAddress\n    );\n\n    /**\n     * @dev Emitted when the implementation of the proxy registered with id is updated\n     * @param id The identifier of the contract\n     * @param proxyAddress The address of the proxy contract\n     * @param oldImplementationAddress The address of the old implementation contract\n     * @param newImplementationAddress The address of the new implementation contract\n     */\n    event AddressSetAsProxy(\n        bytes32 indexed id,\n        address indexed proxyAddress,\n        address oldImplementationAddress,\n        address indexed newImplementationAddress\n    );\n\n    /**\n     * @notice Returns the id of the Aave market to which this contract points to.\n     * @return The market id\n     **/\n    function getMarketId() external view returns (string memory);\n\n    /**\n     * @notice Associates an id with a specific PoolAddressesProvider.\n     * @dev This can be used to create an onchain registry of PoolAddressesProviders to\n     * identify and validate multiple Aave markets.\n     * @param newMarketId The market id\n     */\n    function setMarketId(string calldata newMarketId) external;\n\n    /**\n     * @notice Returns an address by its identifier.\n     * @dev The returned address might be an EOA or a contract, potentially proxied\n     * @dev It returns ZERO if there is no registered address with the given id\n     * @param id The id\n     * @return The address of the registered for the specified id\n     */\n    function getAddress(bytes32 id) external view returns (address);\n\n    /**\n     * @notice General function to update the implementation of a proxy registered with\n     * certain `id`. If there is no proxy registered, it will instantiate one and\n     * set as implementation the `newImplementationAddress`.\n     * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit\n     * setter function, in order to avoid unexpected consequences\n     * @param id The id\n     * @param newImplementationAddress The address of the new implementation\n     */\n    function setAddressAsProxy(\n        bytes32 id,\n        address newImplementationAddress\n    ) external;\n\n    /**\n     * @notice Sets an address for an id replacing the address saved in the addresses map.\n     * @dev IMPORTANT Use this function carefully, as it will do a hard replacement\n     * @param id The id\n     * @param newAddress The address to set\n     */\n    function setAddress(bytes32 id, address newAddress) external;\n\n    /**\n     * @notice Returns the address of the Pool proxy.\n     * @return The Pool proxy address\n     **/\n    function getPool() external view returns (address);\n\n    /**\n     * @notice Updates the implementation of the Pool, or creates a proxy\n     * setting the new `pool` implementation when the function is called for the first time.\n     * @param newPoolImpl The new Pool implementation\n     **/\n    function setPoolImpl(address newPoolImpl) external;\n\n    /**\n     * @notice Returns the address of the PoolConfigurator proxy.\n     * @return The PoolConfigurator proxy address\n     **/\n    function getPoolConfigurator() external view returns (address);\n\n    /**\n     * @notice Updates the implementation of the PoolConfigurator, or creates a proxy\n     * setting the new `PoolConfigurator` implementation when the function is called for the first time.\n     * @param newPoolConfiguratorImpl The new PoolConfigurator implementation\n     **/\n    function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;\n\n    /**\n     * @notice Returns the address of the price oracle.\n     * @return The address of the PriceOracle\n     */\n    function getPriceOracle() external view returns (address);\n\n    /**\n     * @notice Updates the address of the price oracle.\n     * @param newPriceOracle The address of the new PriceOracle\n     */\n    function setPriceOracle(address newPriceOracle) external;\n\n    /**\n     * @notice Returns the address of the ACL manager.\n     * @return The address of the ACLManager\n     */\n    function getACLManager() external view returns (address);\n\n    /**\n     * @notice Updates the address of the ACL manager.\n     * @param newAclManager The address of the new ACLManager\n     **/\n    function setACLManager(address newAclManager) external;\n\n    /**\n     * @notice Returns the address of the ACL admin.\n     * @return The address of the ACL admin\n     */\n    function getACLAdmin() external view returns (address);\n\n    /**\n     * @notice Updates the address of the ACL admin.\n     * @param newAclAdmin The address of the new ACL admin\n     */\n    function setACLAdmin(address newAclAdmin) external;\n\n    /**\n     * @notice Returns the address of the price oracle sentinel.\n     * @return The address of the PriceOracleSentinel\n     */\n    function getPriceOracleSentinel() external view returns (address);\n\n    /**\n     * @notice Updates the address of the price oracle sentinel.\n     * @param newPriceOracleSentinel The address of the new PriceOracleSentinel\n     **/\n    function setPriceOracleSentinel(address newPriceOracleSentinel) external;\n\n    /**\n     * @notice Returns the address of the data provider.\n     * @return The address of the DataProvider\n     */\n    function getPoolDataProvider() external view returns (address);\n\n    /**\n     * @notice Updates the address of the data provider.\n     * @param newDataProvider The address of the new DataProvider\n     **/\n    function setPoolDataProvider(address newDataProvider) external;\n}\n"
      },
      "contracts/src/interfaces/Balancer/IBalancerVault.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IBalancerVault {\n  // Pools\n  //\n  // There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced\n  // functionality:\n  //\n  //  - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the\n  // balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads),\n  // which increase with the number of registered tokens.\n  //\n  //  - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the\n  // balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted\n  // constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are\n  // independent of the number of registered tokens.\n  //\n  //  - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like\n  // minimal swap info Pools, these are called via IMinimalSwapInfoPool.\n\n  enum PoolSpecialization {\n    GENERAL,\n    MINIMAL_SWAP_INFO,\n    TWO_TOKEN\n  }\n\n  /**\n   * @dev Returns a Pool's contract address and specialization setting.\n   */\n  function getPool(bytes32 poolId) external view returns (address, PoolSpecialization);\n\n  // Swaps\n  //\n  // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,\n  // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be\n  // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.\n  //\n  // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.\n  // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),\n  // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').\n  // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together\n  // individual swaps.\n  //\n  // There are two swap kinds:\n  //  - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the\n  // `onSwap` hook) the amount of tokens out (to send to the recipient).\n  //  - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines\n  // (via the `onSwap` hook) the amount of tokens in (to receive from the sender).\n  //\n  // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with\n  // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated\n  // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended\n  // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at\n  // the final intended token.\n  //\n  // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal\n  // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes\n  // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost\n  // much less gas than they would otherwise.\n  //\n  // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple\n  // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only\n  // updating the Pool's internal accounting).\n  //\n  // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token\n  // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the\n  // minimum amount of tokens to receive (by passing a negative value) is specified.\n  //\n  // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after\n  // this point in time (e.g. if the transaction failed to be included in a block promptly).\n  //\n  // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do\n  // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be\n  // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the\n  // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).\n  //\n  // Finally, Internal Balance can be used when either sending or receiving tokens.\n\n  enum SwapKind {\n    GIVEN_IN,\n    GIVEN_OUT\n  }\n\n  /**\n   * @dev Performs a swap with a single Pool.\n   *\n   * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens\n   * taken from the Pool, which must be greater than or equal to `limit`.\n   *\n   * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens\n   * sent to the Pool, which must be less than or equal to `limit`.\n   *\n   * Internal Balance usage and the recipient are determined by the `funds` struct.\n   *\n   * Emits a `Swap` event.\n   */\n  function swap(\n    SingleSwap memory singleSwap,\n    FundManagement memory funds,\n    uint256 limit,\n    uint256 deadline\n  ) external payable returns (uint256);\n\n  /**\n   * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on\n   * the `kind` value.\n   *\n   * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).\n   * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.\n   *\n   * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be\n   * used to extend swap behavior.\n   */\n  struct SingleSwap {\n    bytes32 poolId;\n    SwapKind kind;\n    address assetIn;\n    address assetOut;\n    uint256 amount;\n    bytes userData;\n  }\n\n  /**\n   * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the\n   * `recipient` account.\n   *\n   * If the caller is not `sender`, it must be an authorized relayer for them.\n   *\n   * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20\n   * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`\n   * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of\n   * `joinPool`.\n   *\n   * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of\n   * transferred. This matches the behavior of `exitPool`.\n   *\n   * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a\n   * revert.\n   */\n  struct FundManagement {\n    address sender;\n    bool fromInternalBalance;\n    address payable recipient;\n    bool toInternalBalance;\n  }\n\n  /**\n   * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n   * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n   * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n   * `getPoolTokenInfo`).\n   *\n   * If the caller is not `sender`, it must be an authorized relayer for them.\n   *\n   * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n   * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n   * it just enforces these minimums.\n   *\n   * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n   * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n   * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n   *\n   * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n   * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n   * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n   * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n   *\n   * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n   * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n   * do so will trigger a revert.\n   *\n   * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n   * `tokens` array. This array must match the Pool's registered tokens.\n   *\n   * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n   * their own custom logic. This typically requires additional information from the user (such as the expected number\n   * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n   * passed directly to the Pool's contract.\n   *\n   * Emits a `PoolBalanceChanged` event.\n   */\n  function exitPool(\n    bytes32 poolId,\n    address sender,\n    address payable recipient,\n    ExitPoolRequest memory request\n  ) external;\n\n  struct ExitPoolRequest {\n    address[] assets;\n    uint256[] minAmountsOut;\n    bytes userData;\n    bool toInternalBalance;\n  }\n\n  enum ExitKind {\n    EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,\n    EXACT_BPT_IN_FOR_TOKENS_OUT,\n    BPT_IN_FOR_EXACT_TOKENS_OUT\n  }\n\n  function joinPool(\n    bytes32 poolId,\n    address sender,\n    address recipient,\n    JoinPoolRequest memory request\n  ) external payable;\n\n  struct JoinPoolRequest {\n    address[] assets;\n    uint256[] maxAmountsIn;\n    bytes userData;\n    bool fromInternalBalance;\n  }\n\n  enum JoinKind {\n    INIT,\n    EXACT_TOKENS_IN_FOR_BPT_OUT,\n    TOKEN_IN_FOR_EXACT_BPT_OUT\n  }\n\n  function getPoolTokenInfo(\n    bytes32 poolId,\n    IERC20 token\n  )\n    external\n    view\n    returns (uint256 cash, uint256 managed, uint256 lastChangeBlock, address assetManager);\n\n  function getPoolTokens(\n    bytes32 poolId\n  )\n    external\n    view\n    returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock);\n\n  struct BatchSwapStep {\n    bytes32 poolId;\n    uint256 assetInIndex;\n    uint256 assetOutIndex;\n    uint256 amount;\n    bytes userData;\n  }\n\n  function batchSwap(\n    SwapKind kind,\n    BatchSwapStep[] memory swaps,\n    address[] memory assets,\n    FundManagement memory funds,\n    int256[] memory limits,\n    uint256 deadline\n  ) external payable returns (int256[] memory);\n\n  function flashLoan(\n    address recipient,\n    IERC20[] memory tokens,\n    uint256[] memory amounts,\n    bytes memory userData\n  ) external;\n}\n"
      },
      "contracts/src/interfaces/Balancer/IFlashLoanRecipient.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title IFlashLoanRecipient interface\n * @notice Interface for the IFlashLoanRecipient.\n * @author Sturdy\n * @dev implement this interface to develop a flashloan-compatible IFlashLoanRecipient contract\n **/\ninterface IFlashLoanRecipient {\n  /**\n   * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.\n   *\n   * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this\n   * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the\n   * Vault, or else the entire flash loan will revert.\n   *\n   * `userData` is the same value passed in the `IVault.flashLoan` call.\n   */\n  function receiveFlashLoan(\n    IERC20[] memory tokens,\n    uint256[] memory amounts,\n    uint256[] memory feeAmounts,\n    bytes memory userData\n  ) external;\n}\n"
      },
      "contracts/src/interfaces/Curve/ICurveAddressProvider.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\n/**\n * @title ICurveAddressProvider interface\n * @notice Interface for the Curve Address Provider.\n **/\n\ninterface ICurveAddressProvider {\n  function get_address(uint256 id) external view returns (address);\n}\n"
      },
      "contracts/src/interfaces/Curve/ICurveExchange.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface ICurveExchange {\n  function exchange(\n    address _pool,\n    address _from,\n    address _to,\n    uint256 _amount,\n    uint256 _expected,\n    address _receiver\n  ) external payable returns (uint256);\n\n  function exchange_multiple(\n    address[9] memory _route,\n    uint256[3][4] memory _swap_params,\n    uint256 _amount,\n    uint256 _expected,\n    address[4] memory _pools,\n    address _receiver\n  ) external payable returns (uint256);\n}\n"
      },
      "contracts/src/interfaces/Curve/ICurvePool.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface ICurvePool {\n    function get_virtual_price() external view returns (uint256 price);\n\n    function price_oracle() external view returns (uint256);\n\n    function price_oracle(uint256 i) external view returns (uint256);\n\n    function balances(uint256 _id) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[2] memory _amounts,\n        bool _is_deposit\n    ) external view returns (uint256);\n\n    function calc_token_amount(\n        uint256[] memory _amounts,\n        bool _is_deposit\n    ) external view returns (uint256);\n\n    function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);\n\n    function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);\n\n    function coins(uint256 index) external view returns (address);\n\n    function add_liquidity(uint256[2] memory amounts, uint256 _min_mint_amount) external;\n\n    function add_liquidity(uint256[] memory amounts, uint256 _min_mint_amount) external returns (uint256);\n}"
      },
      "contracts/src/interfaces/IBaseLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface IBaseLeverage {\n  enum FlashLoanType {\n    AAVE,\n    BALANCER\n  }\n\n  enum SwapType {\n    NONE,\n    STAKE,\n    UNSTAKE,\n    DEPOSIT,\n    WITHDRAW,\n    UNISWAP,\n    BALANCER,\n    CURVE\n  }\n\n  struct MultipSwapPath {\n    address[9] routes;\n    uint256[3][4] routeParams;\n    // uniswap/balancer/curve\n    SwapType swapType;\n    uint256 poolCount;\n    address swapFrom;\n    address swapTo;\n    uint256 inAmount;\n    uint256 outAmount;\n  }\n\n  struct BiDirectSwapInfo {\n    MultipSwapPath[4] paths;\n    MultipSwapPath[4] reversePaths;\n    uint256 pathLength;\n  }\n\n  struct UniDirectSwapInfo {\n    MultipSwapPath[4] paths;\n    uint256 pathLength;\n  }\n\n  struct FlashLoanParams {\n    bool isEnterPosition;\n    uint256 minRequiredAmount;\n    address user;\n    address collateralAsset;\n    address silo;\n    BiDirectSwapInfo borrowAssetAndCollateral;\n    BiDirectSwapInfo borrowAssetAndSiloAsset;\n  }\n\n  struct LeverageParams {\n    address user;\n    uint256 principal;\n    uint256 leverage;\n    address borrowAsset;\n    address collateralAsset;\n    address silo;\n    FlashLoanType flashLoanType;\n    BiDirectSwapInfo borrowAssetAndCollateral;\n    BiDirectSwapInfo borrowAssetAndSiloAsset;\n  }\n\n  function enterPositionWithFlashloan(\n    uint256 _principal,\n    uint256 _leverage,\n    address _borrowAsset,\n    address _collateralAsset,\n    address _silo,\n    FlashLoanType _flashLoanType,\n    BiDirectSwapInfo calldata _borrowAssetAndCollateral,\n    BiDirectSwapInfo calldata _borrowAssetAndSiloAsset\n  ) external;\n\n  function withdrawWithFlashloan(\n    uint256 _repayAmount,\n    uint256 _requiredAmount,\n    address _borrowAsset,\n    address _collateralAsset,\n    address _silo,\n    FlashLoanType _flashLoanType,\n    BiDirectSwapInfo calldata _borrowAssetAndSiloAsset,\n    BiDirectSwapInfo calldata _borrowAssetAndCollateral\n  ) external;\n}\n"
      },
      "contracts/src/interfaces/IDualOracle.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.21;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\ninterface IDualOracle is IERC165 {\n    function ORACLE_PRECISION() external view returns (uint256);\n\n    function BASE_TOKEN_0() external view returns (address);\n\n    function BASE_TOKEN_0_DECIMALS() external view returns (uint256);\n\n    function BASE_TOKEN_1() external view returns (address);\n\n    function BASE_TOKEN_1_DECIMALS() external view returns (uint256);\n\n    function decimals() external view returns (uint8);\n\n    function getPricesNormalized() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);\n\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);\n\n    function name() external view returns (string memory);\n\n    function NORMALIZATION_0() external view returns (int256);\n\n    function NORMALIZATION_1() external view returns (int256);\n\n    function QUOTE_TOKEN_0() external view returns (address);\n\n    function QUOTE_TOKEN_0_DECIMALS() external view returns (uint256);\n\n    function QUOTE_TOKEN_1() external view returns (address);\n\n    function QUOTE_TOKEN_1_DECIMALS() external view returns (uint256);\n}\n"
      },
      "contracts/src/interfaces/IERC4626.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity >=0.8.15;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    function asset() external view returns (address);\n\n    function convertToAssets(uint256 shares) external view returns (uint256);\n\n    function convertToShares(uint256 assets) external view returns (uint256);\n\n    function maxDeposit(address) external view returns (uint256);\n\n    function maxMint(address) external view returns (uint256);\n\n    function maxRedeem(address owner) external view returns (uint256);\n\n    function maxWithdraw(address owner) external view returns (uint256);\n\n    function previewDeposit(uint256 assets) external view returns (uint256);\n\n    function previewMint(uint256 shares) external view returns (uint256);\n\n    function previewRedeem(uint256 shares) external view returns (uint256);\n\n    function previewWithdraw(uint256 assets) external view returns (uint256);\n\n    function totalAssets() external view returns (uint256);\n\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) external returns (uint256 assets);\n\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) external returns (uint256 shares);\n}\n"
      },
      "contracts/src/interfaces/IRateCalculator.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity >=0.8.21;\n\ninterface IRateCalculator {\n    function name() external pure returns (string memory);\n\n    function requireValidInitData(bytes calldata _initData) external pure;\n\n    function getConstants() external pure returns (bytes memory _calldata);\n\n    function getNewRate(bytes calldata _data, bytes calldata _initData) external pure returns (uint64 _newRatePerSec);\n}\n"
      },
      "contracts/src/interfaces/IRateCalculatorV2.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\ninterface IRateCalculatorV2 {\n    function name() external view returns (string memory);\n\n    function version() external view returns (uint256, uint256, uint256);\n\n    function getNewRate(\n        uint256 _deltaTime,\n        uint256 _utilization,\n        uint64 _maxInterest\n    ) external view returns (uint64 _newRatePerSec, uint64 _newMaxInterest);\n}\n"
      },
      "contracts/src/interfaces/ISiloGateway.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface ISiloGateway {\n    function borrowAsset(\n        address _silo,\n        uint256 _borrowAmount,\n        uint256 _collateralAmount,\n        address _collateralAsset,\n        address _borrower,\n        address _receiver\n    ) external;\n}\n"
      },
      "contracts/src/interfaces/ISturdyPair.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport { VaultAccount } from \"../libraries/VaultAccount.sol\";\n\ninterface ISturdyPair {\n    struct CurrentRateInfo {\n        uint32 lastBlock;\n        uint32 feeToProtocolRate; // Fee amount 1e5 precision\n        uint64 lastTimestamp;\n        uint64 ratePerSec;\n        uint64 fullUtilizationRate;\n    }\n\n    function CIRCUIT_BREAKER_ADDRESS() external view returns (address);\n\n    function COMPTROLLER_ADDRESS() external view returns (address);\n\n    function DEPLOYER_ADDRESS() external view returns (address);\n\n    function FRAXLEND_WHITELIST_ADDRESS() external view returns (address);\n\n    function timelockAddress() external view returns (address);\n\n    function addCollateral(uint256 _collateralAmount, address _borrower) external;\n    \n    function addInterest(\n        bool _returnAccounting\n    )\n        external\n        returns (\n            uint256 _interestEarned,\n            uint256 _feesAmount,\n            uint256 _feesShare,\n            CurrentRateInfo memory _currentRateInfo,\n            VaultAccount memory _totalAsset,\n            VaultAccount memory _totalBorrow\n        );\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    function approvedBorrowers(address) external view returns (bool);\n\n    function approvedLenders(address) external view returns (bool);\n\n    function approveBorrowDelegation(address _delegatee, uint256 _amount) external;\n\n    function asset() external view returns (address);\n\n    function balanceOf(address account) external view returns (uint256);\n\n    function borrowAsset(\n        uint256 _borrowAmount,\n        uint256 _collateralAmount,\n        address _receiver\n    ) external returns (uint256 _shares);\n\n    function borrowAssetOnBehalfOf(\n        uint256 _borrowAmount,\n        address _onBehalfOf\n    ) external returns (uint256 _shares);\n\n    function borrowerWhitelistActive() external view returns (bool);\n\n    function changeFee(uint32 _newFee) external;\n\n    function cleanLiquidationFee() external view returns (uint256);\n\n    function collateralContract() external view returns (address);\n\n    function currentRateInfo()\n        external\n        view\n        returns (\n            uint32 lastBlock,\n            uint32 feeToProtocolRate,\n            uint64 lastTimestamp,\n            uint64 ratePerSec,\n            uint64 fullUtilizationRate\n        );\n\n    function decimals() external view returns (uint8);\n\n    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\n\n    function deposit(uint256 _amount, address _receiver) external returns (uint256 _sharesReceived);\n\n    function dirtyLiquidationFee() external view returns (uint256);\n\n    function exchangeRateInfo() external view returns (address oracle, uint32 maxOracleDeviation, uint184 lastTimestamp, uint256 lowExchangeRate, uint256 highExchangeRate);\n\n    function getConstants()\n        external\n        pure\n        returns (\n            uint256 _LTV_PRECISION,\n            uint256 _LIQ_PRECISION,\n            uint256 _UTIL_PREC,\n            uint256 _FEE_PRECISION,\n            uint256 _EXCHANGE_PRECISION,\n            uint256 _DEVIATION_PRECISION,\n            uint256 _RATE_PRECISION,\n            uint256 _MAX_PROTOCOL_FEE\n        );\n\n    function getImmutableAddressBool()\n        external\n        view\n        returns (\n            address _assetContract,\n            address _collateralContract,\n            address _oracleMultiply,\n            address _oracleDivide,\n            address _rateContract,\n            address _DEPLOYER_CONTRACT,\n            address _COMPTROLLER_ADDRESS,\n            address _FRAXLEND_WHITELIST,\n            bool _borrowerWhitelistActive,\n            bool _lenderWhitelistActive\n        );\n\n    function getImmutableUint256()\n        external\n        view\n        returns (\n            uint256 _oracleNormalization,\n            uint256 _maxLTV,\n            uint256 _cleanLiquidationFee,\n            uint256 _maturityDate,\n            uint256 _penaltyRate\n        );\n\n    function getPairAccounting()\n        external\n        view\n        returns (\n            uint128 _totalAssetAmount,\n            uint128 _totalAssetShares,\n            uint128 _totalBorrowAmount,\n            uint128 _totalBorrowShares,\n            uint256 _totalCollateral\n        );\n\n    function getUserSnapshot(\n        address _address\n    ) external view returns (uint256 _userAssetShares, uint256 _userBorrowShares, uint256 _userCollateralBalance);\n\n    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\n\n    function lenderWhitelistActive() external view returns (bool);\n\n    function leveragedPosition(\n        address _swapperAddress,\n        uint256 _borrowAmount,\n        uint256 _initialCollateralAmount,\n        uint256 _amountCollateralOutMin,\n        address[] memory _path\n    ) external returns (uint256 _totalCollateralBalance);\n\n    function liquidate(\n        uint128 _sharesToLiquidate,\n        uint256 _deadline,\n        address _borrower\n    ) external returns (uint256 _collateralForLiquidator);\n\n    function maturityDate() external view returns (uint256);\n\n    function maxLTV() external view returns (uint256);\n\n    function maxOracleDelay() external view returns (uint256);\n\n    function name() external view returns (string memory);\n\n    function oracleDivide() external view returns (address);\n\n    function oracleMultiply() external view returns (address);\n\n    function oracleNormalization() external view returns (uint256);\n\n    function owner() external view returns (address);\n\n    function pause() external;\n\n    function paused() external view returns (bool);\n\n    function penaltyRate() external view returns (uint256);\n\n    function rateContract() external view returns (address);\n\n    function redeem(uint256 _shares, address _receiver, address _owner) external returns (uint256 _amountToReturn);\n\n    function removeCollateral(uint256 _collateralAmount, address _receiver) external;\n\n    function removeCollateralFrom(\n        uint256 _collateralAmount,\n        address _receiver,\n        address _borrower\n    ) external;\n\n    function setWhitelistedDelegators(address _delegator, bool _enabled) external;\n\n    function renounceOwnership() external;\n\n    function repayAsset(uint256 _shares, address _borrower) external returns (uint256 _amountToRepay);\n\n    function repayAssetWithCollateral(\n        address _swapperAddress,\n        uint256 _collateralToSwap,\n        uint256 _amountAssetOutMin,\n        address[] memory _path\n    ) external returns (uint256 _amountAssetOut);\n\n    function setApprovedBorrowers(address[] memory _borrowers, bool _approval) external;\n\n    function setApprovedLenders(address[] memory _lenders, bool _approval) external;\n\n    function setMaxOracleDelay(uint256 _newDelay) external;\n\n    function setSwapper(address _swapper, bool _approval) external;\n\n    function setTimelock(address _newAddress) external;\n\n    function swappers(address) external view returns (bool);\n\n    function symbol() external view returns (string memory);\n\n    function toAssetAmount(\n        uint256 _shares,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256);\n\n    function toAssetShares(\n        uint256 _amount,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256);\n\n    function toBorrowAmount(\n        uint256 _shares,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _amount);\n\n    function toBorrowShares(\n        uint256 _amount,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _shares);\n\n    function totalAsset() external view returns (uint128 amount, uint128 shares);\n\n    function totalBorrow() external view returns (uint128 amount, uint128 shares);\n\n    function totalCollateral() external view returns (uint256);\n\n    function totalSupply() external view returns (uint256);\n\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n\n    function transferOwnership(address newOwner) external;\n\n    function unpause() external;\n\n    function updateExchangeRate()\n        external\n        returns (bool _isBorrowAllowed, uint256 _lowExchangeRate, uint256 _highExchangeRate);\n\n    function userBorrowShares(address) external view returns (uint256);\n\n    function userCollateralBalance(address) external view returns (uint256);\n\n    function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch);\n\n    function withdrawFees(uint128 _shares, address _recipient) external returns (uint256 _amountToTransfer);\n\n    function isInterestPaused() external view returns (bool);\n}\n"
      },
      "contracts/src/interfaces/ISturdyPairRegistry.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\ninterface ISturdyPairRegistry {\n    event AddPair(address pairAddress);\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n    event SetDeployer(address deployer, bool _bool);\n\n    function acceptOwnership() external;\n\n    function addPair(address _pairAddress) external;\n\n    function deployedPairsArray(uint256) external view returns (address);\n\n    function deployedPairsByName(string memory) external view returns (address);\n\n    function deployedPairsLength() external view returns (uint256);\n\n    function deployers(address) external view returns (bool);\n\n    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);\n\n    function owner() external view returns (address);\n\n    function pendingOwner() external view returns (address);\n\n    function renounceOwnership() external;\n\n    function setDeployers(address[] memory _deployers, bool _bool) external;\n\n    function transferOwnership(address newOwner) external;\n}\n"
      },
      "contracts/src/interfaces/ISturdyWhitelist.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity >=0.8.21;\n\ninterface ISturdyWhitelist {\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n    event SetSturdyDeployerWhitelist(address indexed _address, bool _bool);\n\n    function acceptOwnership() external;\n\n    function sturdyDeployerWhitelist(address) external view returns (bool);\n\n    function owner() external view returns (address);\n\n    function pendingOwner() external view returns (address);\n\n    function renounceOwnership() external;\n\n    function setSturdyDeployerWhitelist(address[] memory _addresses, bool _bool) external;\n\n    function transferOwnership(address newOwner) external;\n}\n"
      },
      "contracts/src/interfaces/ISwapper.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.21;\n\ninterface ISwapper {\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n}\n"
      },
      "contracts/src/interfaces/Mode/IBaseLeverageWihtoutFlashloan.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface IBaseLeverageWihtoutFlashloan {\n\n  enum SwapType {\n    NONE,\n    DEPOSIT,\n    WITHDRAW,\n    SUPSWAP\n  }\n\n  struct LeverageParams {\n    uint256 principal;\n    uint256 iterations;\n    address borrowAsset;\n    address collateralAsset;\n    address silo;\n    BiDirectSwapInfo borrowAssetAndCollateral;\n  }\n\n  struct MultipSwapPath {\n    address[9] routes;\n    uint256[3][4] routeParams;\n    // supswap\n    SwapType swapType;\n    uint256 poolCount;\n    address swapFrom;\n    address swapTo;\n    uint256 inAmount;\n    uint256 outAmount;\n  }\n\n  struct BiDirectSwapInfo {\n    MultipSwapPath[3] paths;\n    MultipSwapPath[3] reversePaths;\n    uint256 pathLength;\n  }\n\n  struct UniDirectSwapInfo {\n    MultipSwapPath[3] paths;\n    uint256 pathLength;\n  }\n}\n"
      },
      "contracts/src/interfaces/Mode/IBaseLeverageWihtoutFlashloan1.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface IBaseLeverageWihtoutFlashloan1 {\n\n  struct LeverageParams {\n    uint256 principal;\n    uint256 iterations;\n    address borrowAsset;\n    address collateralAsset;\n    address silo;\n  }\n}"
      },
      "contracts/src/interfaces/Mode/Kim/IKimRouter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface IKimRouter {\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        address referrer,\n        uint deadline\n    ) external;\n}"
      },
      "contracts/src/interfaces/Mode/Supswap/ISupV3SwapCallback.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\n/// @title Callback for ISupV3PoolActions#swap\n/// @notice Any contract that calls ISupV3PoolActions#swap must implement this interface\ninterface ISupV3SwapCallback {\n    /// @notice Called to `msg.sender` after executing a swap via ISupV3Pool#swap.\n    /// @dev In the implementation you must pay the pool tokens owed for the swap.\n    /// The caller of this method must be checked to be a SUPV3Pool deployed by the canonical SupV3Factory.\n    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\n    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\n    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\n    /// @param data Any data passed through by the caller via the ISupV3PoolActions#swap call\n    function supV3SwapCallback(\n        int256 amount0Delta,\n        int256 amount1Delta,\n        bytes calldata data\n    ) external;\n}"
      },
      "contracts/src/interfaces/Mode/Supswap/IV3SwapRouter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {ISupV3SwapCallback} from \"./ISupV3SwapCallback.sol\";\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via Sup V3\ninterface IV3SwapRouter is ISupV3SwapCallback {\n    struct ExactInputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another token\n    /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,\n    /// and swap the entire amount, enabling contracts to send tokens before calling this function.\n    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);\n\n    struct ExactInputParams {\n        bytes path;\n        address recipient;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n    /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance,\n    /// and swap the entire amount, enabling contracts to send tokens before calling this function.\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);\n\n    struct ExactOutputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another token\n    /// that may remain in the router after the swap.\n    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);\n\n    struct ExactOutputParams {\n        bytes path;\n        address recipient;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n    /// that may remain in the router after the swap.\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);\n}"
      },
      "contracts/src/interfaces/Pendle/IPendleMarket.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity 0.8.21;\n\ninterface IPendleMarket {\n    function readTokens() external view returns (address _SY, address _PT, address _YT);\n    function swapSyForExactPt(address receiver, uint256 exactPtOut, bytes calldata data) external returns (uint256 netSyIn, uint256 netSyFee);\n    function isExpired() external view returns (bool);\n}"
      },
      "contracts/src/interfaces/Pendle/IPendleRouter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\n\npragma solidity 0.8.21;\n\ninterface IPendleRouter {\n    struct ApproxParams {\n        uint256 guessMin;\n        uint256 guessMax;\n        uint256 guessOffchain; // pass 0 in to skip this variable\n        uint256 maxIteration; // every iteration, the diff between guessMin and guessMax will be divided by 2\n        uint256 eps; // the max eps between the returned result & the correct result, base 1e18. Normally this number will be set\n        // to 1e15 (1e18/1000 = 0.1%)\n    }\n\n    struct LimitOrderData {\n        address limitRouter;\n        uint256 epsSkipMarket; // only used for swap operations, will be ignored otherwise\n        FillOrderParams[] normalFills;\n        FillOrderParams[] flashFills;\n        bytes optData;\n    }\n\n    struct FillOrderParams {\n       Order order;\n        bytes signature;\n        uint256 makingAmount;\n    }\n\n    struct Order {\n        uint256 salt;\n        uint256 expiry;\n        uint256 nonce;\n        OrderType orderType;\n        address token;\n        address YT;\n        address maker;\n        address receiver;\n        uint256 makingAmount;\n        uint256 lnImpliedRate;\n        uint256 failSafeRate;\n        bytes permit;\n    }\n\n    enum OrderType {\n        SY_FOR_PT,\n        PT_FOR_SY,\n        SY_FOR_YT,\n        YT_FOR_SY\n    }\n\n    function addLiquiditySingleSy(\n        address receiver,\n        address market,\n        uint256 netSyIn,\n        uint256 minLpOut,\n        ApproxParams calldata guessPtReceivedFromSy,\n        LimitOrderData calldata limit\n    ) external returns (uint256 netLpOut, uint256 netSyFee);\n\n    function removeLiquiditySingleSy(\n        address receiver,\n        address market,\n        uint256 netLpToRemove,\n        uint256 minSyOut,\n        LimitOrderData calldata limit\n    ) external returns (uint256 netSyOut, uint256 netSyFee);\n\n    function swapExactPtForSy(\n        address receiver,\n        address market,\n        uint256 exactPtIn,\n        uint256 minSyOut,\n        LimitOrderData calldata limit\n    ) external returns (uint256 netSyOut, uint256 netSyFee);\n\n    function swapExactSyForPt(\n        address receiver,\n        address market,\n        uint256 exactSyIn,\n        uint256 minPtOut,\n        ApproxParams calldata guessPtOut,\n        LimitOrderData calldata limit\n    ) external returns (uint256 netPtOut, uint256 netSyFee);\n}"
      },
      "contracts/src/interfaces/Pendle/ISY.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity 0.8.21;\n\ninterface ISY {\n     function deposit(\n        address receiver,\n        address tokenIn,\n        uint256 amountTokenToDeposit,\n        uint256 minSharesOut\n    ) external payable returns (uint256 amountSharesOut);\n\n    function redeem(\n        address receiver,\n        uint256 amountSharesToRedeem,\n        address tokenOut,\n        uint256 minTokenOut,\n        bool burnFromInternalBalance\n    ) external returns (uint256 amountTokenOut);\n}"
      },
      "contracts/src/interfaces/Uniswap/V3/ISwapRouter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IUniswapV3SwapCallback} from \"./IUniswapV3SwapCallback.sol\";\n\n/// @title Router token swapping functionality\n/// @notice Functions for swapping tokens via Uniswap V3\ninterface ISwapRouter is IUniswapV3SwapCallback {\n    struct ExactInputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 deadline;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another token\n    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInputSingle(\n        ExactInputSingleParams calldata params\n    ) external payable returns (uint256 amountOut);\n\n    struct ExactInputParams {\n        bytes path;\n        address recipient;\n        uint256 deadline;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n    }\n\n    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata\n    /// @return amountOut The amount of the received token\n    function exactInput(\n        ExactInputParams calldata params\n    ) external payable returns (uint256 amountOut);\n\n    struct ExactOutputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 deadline;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another token\n    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutputSingle(\n        ExactOutputSingleParams calldata params\n    ) external payable returns (uint256 amountIn);\n\n    struct ExactOutputParams {\n        bytes path;\n        address recipient;\n        uint256 deadline;\n        uint256 amountOut;\n        uint256 amountInMaximum;\n    }\n\n    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)\n    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata\n    /// @return amountIn The amount of the input token\n    function exactOutput(\n        ExactOutputParams calldata params\n    ) external payable returns (uint256 amountIn);\n\n    // Taken from https://soliditydeveloper.com/uniswap3\n    // Manually added to the interface\n    function refundETH() external payable;\n}\n"
      },
      "contracts/src/interfaces/Uniswap/V3/IUniswapV3SwapCallback.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\n/// @title Callback for IUniswapV3PoolActions#swap\n/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface\ninterface IUniswapV3SwapCallback {\n    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\n    /// @dev In the implementation you must pay the pool tokens owed for the swap.\n    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\n    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\n    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\n    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\n    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\n    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call\n    function uniswapV3SwapCallback(\n        int256 amount0Delta,\n        int256 amount1Delta,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "contracts/src/interfaces/Yearn/IYearnVault.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\ninterface IYearnVault {\n    function pricePerShare() external view returns (uint256 price);\n\n    function deposit(uint256 _amount, address recipient) external returns (uint256);\n\n    function withdraw(\n        uint256 maxShares,\n        address recipient,\n        uint256 maxLoss\n    ) external returns (uint256);\n}"
      },
      "contracts/src/leverages/BaseLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport {IBaseLeverage} from \"../interfaces/IBaseLeverage.sol\";\nimport {IFlashLoanReceiver} from \"../interfaces/Aave/V3/IFlashLoanReceiver.sol\";\nimport {IFlashLoanRecipient} from \"../interfaces/Balancer/IFlashLoanRecipient.sol\";\nimport {IPool} from \"../interfaces/Aave/V3/IPool.sol\";\nimport {IBalancerVault} from \"../interfaces/Balancer/IBalancerVault.sol\";\nimport {BalancerswapAdapter} from \"../swappers/BalancerswapAdapter.sol\";\nimport {UniswapAdapter} from \"../swappers/UniswapAdapter.sol\";\nimport {CurveswapAdapter} from \"../swappers/CurveswapAdapter.sol\";\n\nabstract contract BaseLeverage is IFlashLoanReceiver, IFlashLoanRecipient, ReentrancyGuard {\n  using SafeERC20 for IERC20;\n\n  error LV_INVALID_CONFIGURATION();\n  error LV_AMOUNT_NOT_GT_0();\n  error LV_SUPPLY_NOT_ALLOWED();\n  error LV_SUPPLY_FAILED();\n\n  address private constant AAVE_LENDING_POOL_ADDRESS = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;\n\n  address private constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;\n\n  uint256 private constant PERCENTAGE_FACTOR = 100_00;\n\n  //1 == not inExec\n  //2 == inExec;\n  //setting default to 1 to save some gas.\n  uint256 private _balancerFlashLoanLock = 1;\n\n  /**\n   * This function is called after your contract has received the flash loaned amount\n   * overriding executeOperation() in IFlashLoanReceiver\n   */\n  function executeOperation(\n    address[] calldata assets,\n    uint256[] calldata amounts,\n    uint256[] calldata premiums,\n    address initiator,\n    bytes calldata params\n  ) external override returns (bool) {\n    if (initiator != address(this)) revert LV_INVALID_CONFIGURATION();\n    if (msg.sender != AAVE_LENDING_POOL_ADDRESS) revert LV_INVALID_CONFIGURATION();\n    if (assets.length != amounts.length) revert LV_INVALID_CONFIGURATION();\n    if (assets.length != premiums.length) revert LV_INVALID_CONFIGURATION();\n    if (amounts[0] == 0) revert LV_INVALID_CONFIGURATION();\n    if (assets[0] == address(0)) revert LV_INVALID_CONFIGURATION();\n\n    _executeOperation(assets[0], amounts[0], premiums[0], params);\n\n    // approve the Aave LendingPool contract allowance to *pull* the owed amount\n    IERC20(assets[0]).safeApprove(AAVE_LENDING_POOL_ADDRESS, 0);\n    IERC20(assets[0]).safeApprove(AAVE_LENDING_POOL_ADDRESS, amounts[0] + premiums[0]);\n\n    return true;\n  }\n\n  /**\n   * This function is called after your contract has received the flash loaned amount\n   * overriding receiveFlashLoan() in IFlashLoanRecipient\n   */\n  function receiveFlashLoan(\n    IERC20[] memory tokens,\n    uint256[] memory amounts,\n    uint256[] memory feeAmounts,\n    bytes memory userData\n  ) external override {\n    if (msg.sender != BALANCER_VAULT) revert LV_INVALID_CONFIGURATION();\n    if (_balancerFlashLoanLock != 2) revert LV_INVALID_CONFIGURATION();\n    if (tokens.length != amounts.length) revert LV_INVALID_CONFIGURATION();\n    if (tokens.length != feeAmounts.length) revert LV_INVALID_CONFIGURATION();\n    if (amounts[0] == 0) revert LV_INVALID_CONFIGURATION();\n    if (address(tokens[0]) == address(0)) revert LV_INVALID_CONFIGURATION();\n\n    _balancerFlashLoanLock = 1;\n\n    _executeOperation(address(tokens[0]), amounts[0], feeAmounts[0], userData);\n\n    // send tokens to Balancer vault contract\n    IERC20(tokens[0]).safeTransfer(msg.sender, amounts[0] + feeAmounts[0]);\n  }\n\n  function _executeOperation(\n    address asset,\n    uint256 borrowAmount,\n    uint256 fee,\n    bytes memory params\n  ) internal {\n    // parse params\n    IBaseLeverage.FlashLoanParams memory opsParams = abi.decode(\n      params,\n      (IBaseLeverage.FlashLoanParams)\n    );\n    if (opsParams.minRequiredAmount == 0) revert LV_INVALID_CONFIGURATION();\n    if (opsParams.user == address(0)) revert LV_INVALID_CONFIGURATION();\n\n    if (opsParams.isEnterPosition) {\n      _enterPositionWithFlashloan(asset, borrowAmount, fee, opsParams);\n    } else {\n      _withdrawWithFlashloan(asset, borrowAmount, opsParams);\n    }\n  }\n\n  /**\n   * @param _principal - The amount of collateral\n   * @param _leverage - Extra leverage value and must be greater than 0, ex. 300% = 300_00\n   *                    _principal + _principal * _leverage should be used as collateral\n   * @param _borrowAsset - The flashloan borrowing asset address when leverage works\n   * @param _collateralAsset - The collateral asset address when leverage works\n   * @param _silo - The silo address\n   * @param _flashLoanType - 0 is Aave, 1 is Balancer\n   * @param _borrowAssetAndCollateral - The uniswap/balancer/curve swap paths between borrowAsset and collateral\n   * @param _borrowAssetAndSiloAsset - The uniswap/balancer/curve swap paths between borrowAsset and silo asset\n   */\n  function enterPositionWithFlashloan(\n    uint256 _principal,\n    uint256 _leverage,\n    address _borrowAsset,\n    address _collateralAsset,\n    address _silo,\n    IBaseLeverage.FlashLoanType _flashLoanType,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndCollateral,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndSiloAsset\n  ) external nonReentrant {\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_leverage == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_leverage >= 900_00) revert LV_INVALID_CONFIGURATION();\n    if (_borrowAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_silo == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_collateralAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_NOT_ALLOWED();\n\n    IERC20(_collateralAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    _leverageWithFlashloan(\n      IBaseLeverage.LeverageParams(\n        msg.sender,\n        _principal,\n        _leverage,\n        _borrowAsset,\n        _collateralAsset,\n        _silo,\n        _flashLoanType,\n        _borrowAssetAndCollateral,\n        _borrowAssetAndSiloAsset\n      )\n    );\n  }\n\n  /**\n   * @param _repayAmount - The amount of repay\n   * @param _requiredAmount - The amount of collateral\n   * @param _borrowAsset - The flashloan borrowing asset address when leverage works\n   * @param _collateralAsset - The collateral asset address when leverage works\n   * @param _silo - The silo address\n   * @param _flashLoanType - 0 is Aave, 1 is Balancer\n   * @param _borrowAssetAndCollateral - The uniswap/balancer/curve swap paths between borrowAsset and collateral asset\n   * @param _borrowAssetAndSiloAsset - The uniswap/balancer/curve swap paths between borrowAsset and silo asset\n   */\n  function withdrawWithFlashloan(\n    uint256 _repayAmount,\n    uint256 _requiredAmount,\n    address _borrowAsset,\n    address _collateralAsset,\n    address _silo,\n    IBaseLeverage.FlashLoanType _flashLoanType,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndCollateral,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndSiloAsset\n  ) external nonReentrant {\n    if (_repayAmount == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_requiredAmount == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_borrowAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_silo == address(0)) revert LV_INVALID_CONFIGURATION();\n\n    uint256[] memory amounts = new uint256[](1);\n    amounts[0] = _borrowAssetAndSiloAsset.paths[0].inAmount;\n    if (amounts[0] == 0) {\n      amounts[0] = _repayAmount;\n    }\n\n    bytes memory params = abi.encode(\n      false /*leavePosition*/,\n      _repayAmount,\n      msg.sender,\n      _collateralAsset,\n      _silo,\n      _borrowAssetAndCollateral,\n      _borrowAssetAndSiloAsset\n    );\n\n    if (_flashLoanType == IBaseLeverage.FlashLoanType.AAVE) {\n      // 0 means revert the transaction if not validated\n      uint256[] memory modes = new uint256[](1);\n      modes[0] = 0;\n\n      address[] memory assets = new address[](1);\n      assets[0] = _borrowAsset;\n      IPool(AAVE_LENDING_POOL_ADDRESS).flashLoan(\n        address(this),\n        assets,\n        amounts,\n        modes,\n        address(this),\n        params,\n        0\n      );\n    } else {\n      if (_balancerFlashLoanLock != 1) revert LV_INVALID_CONFIGURATION();\n      IERC20[] memory assets = new IERC20[](1);\n      assets[0] = IERC20(_borrowAsset);\n      _balancerFlashLoanLock = 2;\n      IBalancerVault(BALANCER_VAULT).flashLoan(address(this), assets, amounts, params);\n    }\n\n    // remained borrow asset -> collateral\n    _swapAsset(\n      _borrowAsset,\n      _collateralAsset,\n      IERC20(_borrowAsset).balanceOf(address(this)),\n      _borrowAssetAndCollateral.paths,\n      _borrowAssetAndCollateral.pathLength,\n      false\n    );\n\n    uint256 collateralAmount = IERC20(_collateralAsset).balanceOf(address(this));\n    if (collateralAmount > _requiredAmount) {\n      _supply(_collateralAsset, _silo, collateralAmount - _requiredAmount, msg.sender);\n      collateralAmount = _requiredAmount;\n    }\n\n    // finally deliver the collateral to user\n    IERC20(_collateralAsset).safeTransfer(msg.sender, collateralAmount);\n  }\n\n  /**\n   * @param _principal - The amount of zapping asset\n   * @param _borrowAmount - The amount of borrowing asset\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _collateralAsset - The collateral asset address\n   * @param _silo - The silo address\n   * @param _zapAssetToCollateral - The uniswap/balancer/curve swap paths from zappingAsset to collateral asset\n   */\n  function zapDeposit(\n    uint256 _principal,\n    uint256 _borrowAmount,\n    address _zappingAsset,\n    address _collateralAsset,\n    address _silo,\n    IBaseLeverage.UniDirectSwapInfo calldata _zapAssetToCollateral\n  ) external nonReentrant {\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_silo == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _zappingAsset, \n      _collateralAsset, \n      _principal, \n      _zapAssetToCollateral.paths, \n      _zapAssetToCollateral.pathLength, \n      true\n    );\n    \n    // deposit collateral\n    _supply(_collateralAsset, _silo, collateralAmount, msg.sender);\n\n    //borrow\n    if (_borrowAmount != 0) {\n      _borrow(_silo, _borrowAmount, msg.sender, msg.sender);\n    }\n  }\n\n  /**\n   * @param _principal - The amount of the zapping asset\n   * @param _leverage - Extra leverage value and must be greater than 0, ex. 300% = 300_00\n   *                    principal + principal * leverage should be used as collateral\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _collateralAsset - The collateral asset address when leverage works\n   * @param _borrowAsset - The flashloan borrowing asset address when leverage works\n   * @param _silo - The silo address\n   * @param _flashLoanType - 0 is Aave, 1 is Balancer\n   * @param _zapAssetToCollateral - The uniswap/balancer/curve swap paths from zappingAsset to collateral asset\n   * @param _borrowAssetAndCollateral - The uniswap/balancer/curve swap path length between borrowAsset and collateral asset\n   * @param _borrowAssetAndSiloAsset - The uniswap/balancer/curve swap between borrowAsset and collateralAsset\n   */\n  function zapLeverageWithFlashloan(\n    uint256 _principal,\n    uint256 _leverage,\n    address _zappingAsset,\n    address _collateralAsset,\n    address _borrowAsset,\n    address _silo,\n    IBaseLeverage.FlashLoanType _flashLoanType,\n    IBaseLeverage.UniDirectSwapInfo calldata _zapAssetToCollateral,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndCollateral,\n    IBaseLeverage.BiDirectSwapInfo calldata _borrowAssetAndSiloAsset\n  ) external nonReentrant {\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_leverage == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_leverage >= 900_00) revert LV_INVALID_CONFIGURATION();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_borrowAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_silo == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _zappingAsset, \n      _collateralAsset, \n      _principal, \n      _zapAssetToCollateral.paths, \n      _zapAssetToCollateral.pathLength, \n      true\n    );\n\n    _leverageWithFlashloan(\n      IBaseLeverage.LeverageParams(\n        msg.sender,\n        collateralAmount,\n        _leverage,\n        _borrowAsset,\n        _collateralAsset,\n        _silo,\n        _flashLoanType,\n        _borrowAssetAndCollateral,\n        _borrowAssetAndSiloAsset\n      )\n    );\n  }\n\n  function _leverageWithFlashloan(IBaseLeverage.LeverageParams memory _params) internal {\n    uint256 minCollateralAmount = _params.principal * (PERCENTAGE_FACTOR + _params.leverage) / PERCENTAGE_FACTOR;\n\n    bytes memory params = abi.encode(\n      true /*enterPosition*/,\n      minCollateralAmount,\n      _params.user,\n      _params.collateralAsset,\n      _params.silo,\n      _params.borrowAssetAndCollateral,\n      _params.borrowAssetAndSiloAsset\n    );\n\n    uint256[] memory amounts = new uint256[](1);\n    amounts[0] = _params.borrowAssetAndCollateral.paths[0].inAmount;\n    if (_params.flashLoanType == IBaseLeverage.FlashLoanType.AAVE) {\n      // 0 means revert the transaction if not validated\n      uint256[] memory modes = new uint256[](1);\n      address[] memory assets = new address[](1);\n      assets[0] = _params.borrowAsset;\n      IPool(AAVE_LENDING_POOL_ADDRESS).flashLoan(\n        address(this),\n        assets,\n        amounts,\n        modes,\n        address(this),\n        params,\n        0\n      );\n    } else {\n      if (_balancerFlashLoanLock != 1) revert LV_INVALID_CONFIGURATION();\n\n      IERC20[] memory assets = new IERC20[](1);\n      assets[0] = IERC20(_params.borrowAsset);\n      _balancerFlashLoanLock = 2;\n      IBalancerVault(BALANCER_VAULT).flashLoan(address(this), assets, amounts, params);\n      _balancerFlashLoanLock = 1;\n    }\n\n    _afterLeverageWithFlashloan(\n      _params.borrowAsset,\n      _params\n    );\n  }\n\n  function _swapAsset(\n    address _fromAsset,\n    address _toAsset,\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath[4] memory _paths,\n    uint256 _pathLength,\n    bool _checkOutAmount\n  ) internal returns (uint256) {\n    if (_pathLength == 0) revert LV_INVALID_CONFIGURATION();\n    if (_paths[0].swapFrom != _fromAsset) revert LV_INVALID_CONFIGURATION();\n    if (_paths[_pathLength - 1].swapTo != _toAsset) revert LV_INVALID_CONFIGURATION();\n\n    uint256 amount = _amount;\n    if (amount == 0) return 0;\n\n    for (uint256 i; i < _pathLength; ++i) {\n      if (_paths[i].swapType == IBaseLeverage.SwapType.NONE) continue;\n\n      amount = _processSwap(amount, _paths[i], _checkOutAmount);\n    }\n\n    return amount;\n  }\n\n  function _swapByPath(\n    uint256 _fromAmount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal returns (uint256) {\n    uint256 poolCount = _path.poolCount;\n    uint256 outAmount = _checkOutAmount ? _path.outAmount : 0;\n    if (poolCount == 0) revert LV_INVALID_CONFIGURATION();\n\n    if (_path.swapType == IBaseLeverage.SwapType.BALANCER) {\n      // Balancer Swap\n      BalancerswapAdapter.Path memory path;\n      path.tokens = new address[](poolCount + 1);\n      path.poolIds = new bytes32[](poolCount);\n\n      for (uint256 i; i < poolCount; ++i) {\n        path.tokens[i] = _path.routes[i * 2];\n        path.poolIds[i] = bytes32(_path.routeParams[i][0]);\n      }\n      path.tokens[poolCount] = _path.routes[poolCount * 2];\n\n      return\n        BalancerswapAdapter.swapExactTokensForTokens(\n          _path.swapFrom,\n          _path.swapTo,\n          _fromAmount,\n          path,\n          outAmount\n        );\n    }\n\n    if (_path.swapType == IBaseLeverage.SwapType.UNISWAP) {\n      // UniSwap\n      UniswapAdapter.Path memory path;\n      path.tokens = new address[](poolCount + 1);\n      path.fees = new uint256[](poolCount);\n\n      for (uint256 i; i < poolCount; ++i) {\n        path.tokens[i] = _path.routes[i * 2];\n        path.fees[i] = _path.routeParams[i][0];\n      }\n      path.tokens[poolCount] = _path.routes[poolCount * 2];\n\n      return\n        UniswapAdapter.swapExactTokensForTokens(\n          _path.swapFrom,\n          _path.swapTo,\n          _fromAmount,\n          path,\n          outAmount\n        );\n    }\n\n    // Curve Swap\n    return\n      CurveswapAdapter.swapExactTokensForTokens(\n        _path.swapFrom,\n        _path.swapTo,\n        _fromAmount,\n        CurveswapAdapter.Path(_path.routes, _path.routeParams),\n        outAmount\n      );\n  }\n\n  function _enterPositionWithFlashloan(\n    address _borrowAsset,\n    uint256 _borrowedAmount,\n    uint256 _fee,\n    IBaseLeverage.FlashLoanParams memory _params\n  ) internal virtual;\n\n  function _afterLeverageWithFlashloan(\n    address _borrowAsset,\n    IBaseLeverage.LeverageParams memory _params\n  ) internal virtual;\n\n  function _withdrawWithFlashloan(\n    address _borrowAsset,\n    uint256 _borrowedAmount,\n    IBaseLeverage.FlashLoanParams memory _params\n  ) internal virtual;\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal virtual;\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal virtual;\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal virtual;\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal virtual;\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal virtual returns (uint256);\n}"
      },
      "contracts/src/leverages/CrvYearnVaultLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {SturdyLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./SturdyLeverage.sol\";\nimport {IYearnVault} from \"../interfaces/Yearn/IYearnVault.sol\";\n\n/// @notice  Leverage contract for yearn vault of curve lp token\ncontract CrvYearnVaultLeverage is SturdyLeverage {\n  using SafeERC20 for IERC20;\n\n  error LV_REQUIRE_MIN_AMOUNT();\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal override returns (uint256) {\n    if (_path.swapType > IBaseLeverage.SwapType.WITHDRAW) {\n      return _swapByPath(_amount, _path, _checkOutAmount);\n    }\n\n    if (_path.swapType == IBaseLeverage.SwapType.WITHDRAW) {\n      // Yearn Vault LP -> Curve Pool LP\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n\n      // Withdraw from Yearn Vault and receive Curve LP token\n      uint256 outAmount = IYearnVault(_path.swapFrom).withdraw(_amount, address(this), 1);\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    }\n\n    // Curve Pool LP -> Yearn Vault LP\n    // Deposit Curve LP token to Yearn Vault and receive Yearn Vault LP token\n    address asset = _path.swapFrom;\n    address vault = _path.swapTo;\n    IERC20(asset).safeApprove(vault, 0);\n    IERC20(asset).safeApprove(vault, _amount);\n    uint256 outAmount = IYearnVault(vault).deposit(_amount, address(this));\n\n    if (_checkOutAmount && outAmount < _path.outAmount) {\n      revert LV_REQUIRE_MIN_AMOUNT();\n    }\n  \n    return outAmount;\n  }\n}"
      },
      "contracts/src/leverages/CrvYearnVaultLeverage2.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {SturdyLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./SturdyLeverage.sol\";\nimport {IYearnVault} from \"../interfaces/Yearn/IYearnVault.sol\";\nimport {ICurvePool} from \"../interfaces/Curve/ICurvePool.sol\";\n\n/// @notice  Leverage contract for yearn vault of curve lp token\ncontract CrvYearnVaultLeverage2 is SturdyLeverage {\n  using SafeERC20 for IERC20;\n\n  address public immutable YEARN_VAULT;\n\n  error LV_REQUIRE_MIN_AMOUNT();\n\n  constructor(\n      address _yearnVault\n  ) {\n    YEARN_VAULT = _yearnVault;\n  }\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal override returns (uint256) {\n    if (_path.swapType > IBaseLeverage.SwapType.WITHDRAW) {\n      return _swapByPath(_amount, _path, _checkOutAmount);\n    }\n\n    if (_path.swapType == IBaseLeverage.SwapType.WITHDRAW) {\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n      \n      // Withdraw from Yearn Vault and receive Curve LP token\n      uint256 outAmount = IYearnVault(_path.swapFrom).withdraw(_amount, address(this), 1);\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    }\n\n    address asset = _path.swapFrom;\n    address vault = _path.swapTo;\n    uint256 outAmount;\n\n    IERC20(asset).safeApprove(vault, 0);\n    IERC20(asset).safeApprove(vault, _amount);\n\n    if (vault == YEARN_VAULT) {\n      // Deposit Curve LP token to Yearn Vault and receive Yearn Vault LP token\n      outAmount = IYearnVault(vault).deposit(_amount, address(this));\n    } else {\n      // Deposit asset to Curve pool and receive LP token.\n      uint256[] memory amounts = new uint256[](2);\n      for (uint256 i; i < 2; ++i) {\n        if (ICurvePool(vault).coins(i) == asset) {\n          amounts[i] = _amount;\n          break;\n        }\n      }\n\n      outAmount = ICurvePool(vault).add_liquidity(amounts, 0);\n    }    \n\n    if (_checkOutAmount && outAmount < _path.outAmount) {\n      revert LV_REQUIRE_MIN_AMOUNT();\n    }\n  \n    return outAmount;\n  }\n}"
      },
      "contracts/src/leverages/ERC4626VaultLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {SturdyLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./SturdyLeverage.sol\";\nimport { IERC4626 } from \"../interfaces/IERC4626.sol\";\n\ncontract ERC4626VaultLeverage is SturdyLeverage {\n  using SafeERC20 for IERC20;\n\n  error LV_REQUIRE_MIN_AMOUNT();\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal override returns (uint256) {\n    if (_path.swapType > IBaseLeverage.SwapType.WITHDRAW) {\n      return _swapByPath(_amount, _path, _checkOutAmount);\n    }\n\n    if (_path.swapType == IBaseLeverage.SwapType.WITHDRAW) {\n      // ERC4626_VAULT_LP -> ASSET\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n\n      // Withdraw from ERC4626 Vault and receive asset\n      uint256 outAmount = IERC4626(_path.swapFrom).redeem(_amount, address(this), address(this));\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    }\n\n    // ASSET -> ERC4626_VAULT_LP\n    // Deposit asset to ERC4626 Vault and receive LP token\n    address asset = _path.swapFrom;\n    address vault = _path.swapTo;\n    IERC20(asset).safeApprove(vault, 0);\n    IERC20(asset).safeApprove(vault, _amount);\n    uint256 outAmount = IERC4626(vault).deposit(_amount, address(this));\n\n    if (_checkOutAmount && outAmount < _path.outAmount) {\n      revert LV_REQUIRE_MIN_AMOUNT();\n    }\n  \n    return outAmount;\n  }\n}"
      },
      "contracts/src/leverages/Mode/BaseLeverageWihtoutFlashloan.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {IBaseLeverageWihtoutFlashloan} from \"../../interfaces/Mode/IBaseLeverageWihtoutFlashloan.sol\";\nimport {ISturdyPair} from \"../../interfaces/ISturdyPair.sol\";\nimport {SupswapAdapter} from \"../../swappers/Mode/SupswapAdapter.sol\";\n\nabstract contract BaseLeverageWihtoutFlashloan is ReentrancyGuard {\n  using SafeERC20 for IERC20;\n\n  uint256 private constant HEALTH_FACTOR = 1e18;\n\n  error LV_INVALID_CONFIGURATION();\n  error LV_AMOUNT_NOT_GT_0();\n  error LV_SUPPLY_NOT_ALLOWED();\n  error LV_SUPPLY_FAILED();\n  error LV_REMOVE_ITERATION_OVER();\n\n  /**\n   * @param _principal - The amount of collateral\n   * @param _iterations - Loop count\n   * @param _silo - The silo address\n   * @param _borrowAssetAndCollateral - The supswap swap paths between borrowing asset and collateral asset\n   */\n  function enterPosition(\n    uint256 _principal,\n    uint256 _iterations,\n    address _silo,\n    IBaseLeverageWihtoutFlashloan.BiDirectSwapInfo calldata _borrowAssetAndCollateral\n  ) external {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (IERC20(collateralAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_NOT_ALLOWED();\n\n    IERC20(collateralAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    _leverage(\n      IBaseLeverageWihtoutFlashloan.LeverageParams(\n        _principal,\n        _iterations,\n        ISturdyPair(_silo).asset(),\n        collateralAsset,\n        _silo,\n        _borrowAssetAndCollateral\n      )\n    );\n  }\n\n  /**\n   * @param _principal - The amount of collateral, uint256 max value should withdraw all collateral\n   * @param _iterations - Loop count\n   * @param _healthFactor - The heathFactor value to keep after leave position, 1 = 1e18\n   * @param _silo - The silo address\n   * @param _borrowAssetAndCollateral - The supswap swap paths between borrowing asset and collateral asset\n   */\n  function leavePosition(\n    uint256 _principal,\n    uint256 _iterations,\n    uint256 _healthFactor,\n    address _silo,\n    IBaseLeverageWihtoutFlashloan.BiDirectSwapInfo calldata _borrowAssetAndCollateral\n  ) external {\n    ISturdyPair pair = ISturdyPair(_silo);\n    address collateralAsset = pair.collateralContract();\n    address borrowAsset = pair.asset();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (borrowAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_healthFactor < 1e18) revert LV_INVALID_CONFIGURATION();\n\n    // reduce leverage to increase healthFactor\n    if (_iterations != 0) {\n      _reduceLeverageWithAmount(\n        _silo, \n        0, \n        _borrowAssetAndCollateral\n      );\n    } else {\n      _reduceLeverageWithAmount(\n        _silo,\n        _principal,\n        _borrowAssetAndCollateral\n      );\n      return;\n    }\n\n    uint256 count;\n    do {\n      // limit loop count\n      if (count >= _iterations) revert LV_REMOVE_ITERATION_OVER();\n\n      // withdraw collateral keeping the healthFactor\n      uint256 availableAmount = _calcWithdrawalAmount(\n        _silo,\n        _healthFactor\n      );\n      if (availableAmount == 0) break;\n\n      uint256 requiredAmount = _principal - IERC20(collateralAsset).balanceOf(address(this));\n      uint256 removeAmount = Math.min(availableAmount, requiredAmount);\n      _remove(removeAmount, _silo, 0, msg.sender);\n\n      if (removeAmount == requiredAmount) break;\n\n      uint256 debtAmount =  pair.toBorrowAmount(pair.userBorrowShares(msg.sender), true, true);\n      if (debtAmount != 0) {\n        // swap collateral to borrowing asset\n        // in this case, some collateral asset maybe remained because of convex (ex: sUSD)\n        uint256 borrowingAssetAmount = _swapAsset(\n          collateralAsset, \n          borrowAsset, \n          IERC20(collateralAsset).balanceOf(address(this)), \n          _borrowAssetAndCollateral.reversePaths,\n          _borrowAssetAndCollateral.pathLength,\n          false\n        );\n        uint256 repayAmount = Math.min(debtAmount, borrowingAssetAmount);\n        // repay\n        _repay(_silo, repayAmount, msg.sender);\n        if (borrowingAssetAmount > repayAmount) {\n          // swap borrowing asset to collateral in case of extra ramined borrowing asset after repay\n          _swapAsset(\n            borrowAsset, \n            collateralAsset, \n            IERC20(borrowAsset).balanceOf(address(this)),\n            _borrowAssetAndCollateral.paths,\n            _borrowAssetAndCollateral.pathLength,\n            false\n          );\n        }\n      }\n\n      count++;\n    } while (true);\n\n    // finally deliver the collateral to user\n    IERC20(collateralAsset).safeTransfer(msg.sender, IERC20(collateralAsset).balanceOf(address(this)));\n  }\n\n  /**\n   * @param _principal - The amount of zapping asset\n   * @param _borrowAmount - The amount of borrowing asset\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _silo - The silo address\n   * @param _zapAssetToCollateral - The supswap swap paths from zapping asset to collateral asset\n   */\n  function zapDeposit(\n    uint256 _principal,\n    uint256 _borrowAmount,\n    address _zappingAsset,\n    address _silo,\n    IBaseLeverageWihtoutFlashloan.UniDirectSwapInfo calldata _zapAssetToCollateral\n  ) external nonReentrant {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _zappingAsset, \n      collateralAsset, \n      _principal,\n      _zapAssetToCollateral.paths,\n      _zapAssetToCollateral.pathLength,\n      true\n    );\n    \n    // deposit collateral\n    _supply(collateralAsset, _silo, collateralAmount, msg.sender);\n\n    //borrow\n    if (_borrowAmount != 0) {\n      _borrow(_silo, _borrowAmount, msg.sender, msg.sender);\n    }\n  }\n\n  /**\n   * @param _principal - The amount of the zapping asset\n   * @param _iterations - Loop count\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _silo - The silo address\n   * @param _zapAssetToCollateral - The supswap swap paths from zapping asset to collateral asset\n   * @param _borrowAssetAndCollateral - The supswap swap paths between borrowing asset and collateral asset\n   */\n  function zapLeverage(\n    uint256 _principal,\n    uint256 _iterations,\n    address _zappingAsset,\n    address _silo,\n    IBaseLeverageWihtoutFlashloan.UniDirectSwapInfo calldata _zapAssetToCollateral,\n    IBaseLeverageWihtoutFlashloan.BiDirectSwapInfo calldata _borrowAssetAndCollateral\n  ) external nonReentrant {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _zappingAsset, \n      collateralAsset, \n      _principal,\n      _zapAssetToCollateral.paths,\n      _zapAssetToCollateral.pathLength,\n      true\n    );\n\n    _leverage(\n      IBaseLeverageWihtoutFlashloan.LeverageParams(\n        collateralAmount,\n        _iterations,\n        ISturdyPair(_silo).asset(),\n        collateralAsset,\n        _silo,\n        _borrowAssetAndCollateral\n      )\n    );\n  }\n\n  function _leverage(IBaseLeverageWihtoutFlashloan.LeverageParams memory _params) internal {\n    uint256 suppliedAmount = _params.principal;\n    uint256 borrowAmount;\n\n    _supply(_params.collateralAsset, _params.silo, suppliedAmount, msg.sender);\n    \n    for (uint256 i; i < _params.iterations; ++i) {\n      borrowAmount = _calcBorrowableAmount(\n        _params.silo,\n        suppliedAmount\n      );\n      bool checkOutAmount = i == 0 ? true : false;\n\n      if (borrowAmount != 0) {\n        // borrow\n        _borrow(_params.silo, borrowAmount, msg.sender, address(this));\n        // swap borrowing asset to collateral\n        suppliedAmount = _swapAsset(\n          _params.borrowAsset, \n          _params.collateralAsset, \n          borrowAmount, \n          _params.borrowAssetAndCollateral.paths,\n          _params.borrowAssetAndCollateral.pathLength,\n          checkOutAmount\n        );\n        // supply to LP\n        _supply(_params.collateralAsset, _params.silo, suppliedAmount, msg.sender);\n      }\n    }\n  }\n\n  function _reduceLeverageWithAmount(\n    address _silo,\n    uint256 _amount,\n    IBaseLeverageWihtoutFlashloan.BiDirectSwapInfo calldata _borrowAssetAndCollateral\n  ) internal {\n    // withdraw available collateral\n    ISturdyPair pair = ISturdyPair(_silo);\n    uint256 requireAmount = _amount;\n    bool checkOutAmount = true;\n\n    do {\n      uint256 debtAmount =  pair.toBorrowAmount(pair.userBorrowShares(msg.sender), true, true);\n      if (debtAmount == 0) break;\n\n      uint256 availableAmount = _calcWithdrawalAmount(\n        _silo,\n        HEALTH_FACTOR\n      );\n      uint256 removeAmount = _amount != 0\n        ? Math.min(availableAmount, requireAmount)\n        : availableAmount;\n      _remove(removeAmount, _silo, 0, msg.sender);\n\n      // swap collateral to borrowing asset\n      // in this case, some collateral asset maybe remained because of convex (ex: sUSD)\n      uint256 borrowingAssetAmount = _swapAsset(\n        pair.collateralContract(), \n        pair.asset(), \n        IERC20(pair.collateralContract()).balanceOf(address(this)),\n        _borrowAssetAndCollateral.reversePaths,\n        _borrowAssetAndCollateral.pathLength,\n        checkOutAmount\n      );\n      if (checkOutAmount) checkOutAmount = false;\n\n      uint256 repayAmount = Math.min(debtAmount, borrowingAssetAmount);\n      // repay\n      _repay(_silo, repayAmount, msg.sender);\n      if (borrowingAssetAmount > repayAmount) {\n        // swap borrowing asset to collateral in case of extra ramined borrowing asset after repay\n        uint256 collateralAmount = _swapAsset(\n          pair.asset(),\n          pair.collateralContract(),\n          IERC20(pair.asset()).balanceOf(address(this)),\n          _borrowAssetAndCollateral.paths,\n          _borrowAssetAndCollateral.pathLength,\n          false\n        );\n        _supply(pair.collateralContract(), _silo, collateralAmount, msg.sender);\n        removeAmount -= collateralAmount;\n      }\n      // one time reduce leverage\n      if (_amount == 0) break;\n\n      requireAmount -= removeAmount;\n      // completed the required amount to reduce leverage\n      if (requireAmount == 0) break;\n    } while (true);\n  }\n\n  function _swapAsset(\n    address _fromAsset,\n    address _toAsset,\n    uint256 _amount,\n    IBaseLeverageWihtoutFlashloan.MultipSwapPath[3] memory _paths,\n    uint256 _pathLength,\n    bool _checkOutAmount\n  ) internal returns (uint256) {\n    if (_pathLength == 0) revert LV_INVALID_CONFIGURATION();\n    if (_paths[0].swapFrom != _fromAsset) revert LV_INVALID_CONFIGURATION();\n    if (_paths[_pathLength - 1].swapTo != _toAsset) revert LV_INVALID_CONFIGURATION();\n\n    uint256 amount = _amount;\n    if (amount == 0) return 0;\n\n    for (uint256 i; i < _pathLength; ++i) {\n      if (_paths[i].swapType == IBaseLeverageWihtoutFlashloan.SwapType.NONE) continue;\n\n      amount = _processSwap(amount, _paths[i], _checkOutAmount);\n    }\n\n    return amount;\n  }\n\n  function _swapByPath(\n    uint256 _fromAmount,\n    IBaseLeverageWihtoutFlashloan.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal returns (uint256) {\n    uint256 poolCount = _path.poolCount;\n    uint256 outAmount = _checkOutAmount ? _path.outAmount : 0;\n    if (poolCount == 0) revert LV_INVALID_CONFIGURATION();\n\n    // Supswap\n    SupswapAdapter.Path memory path;\n    path.tokens = new address[](poolCount + 1);\n    path.fees = new uint256[](poolCount);\n\n    for (uint256 i; i < poolCount; ++i) {\n      path.tokens[i] = _path.routes[i * 2];\n      path.fees[i] = _path.routeParams[i][0];\n    }\n    path.tokens[poolCount] = _path.routes[poolCount * 2];\n\n    return\n      SupswapAdapter.swapExactTokensForTokens(\n        _path.swapFrom,\n        _path.swapTo,\n        _fromAmount,\n        path,\n        outAmount\n      );\n  }\n\n  function _calcBorrowableAmount(\n    address _silo,\n    uint256 _collateralAmount\n  ) internal virtual returns (uint256);\n\n  function _calcWithdrawalAmount(\n    address _silo,\n    uint256 _healthFactor\n  ) internal virtual returns (uint256);\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal virtual;\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal virtual;\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal virtual;\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal virtual;\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverageWihtoutFlashloan.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal virtual returns (uint256);\n}"
      },
      "contracts/src/leverages/Mode/BaseLeverageWihtoutFlashloan1.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {IBaseLeverageWihtoutFlashloan1} from \"../../interfaces/Mode/IBaseLeverageWihtoutFlashloan1.sol\";\nimport {ISturdyPair} from \"../../interfaces/ISturdyPair.sol\";\n\nabstract contract BaseLeverageWihtoutFlashloan1 is ReentrancyGuard {\n  using SafeERC20 for IERC20;\n\n  uint256 private constant HEALTH_FACTOR = 1e18;\n\n  error LV_INVALID_CONFIGURATION();\n  error LV_AMOUNT_NOT_GT_0();\n  error LV_SUPPLY_NOT_ALLOWED();\n  error LV_SUPPLY_FAILED();\n  error LV_REMOVE_ITERATION_OVER();\n\n  /**\n   * @param _principal - The amount of collateral\n   * @param _iterations - Loop count\n   * @param _silo - The silo address\n   */\n  function enterPosition(\n    uint256 _principal,\n    uint256 _iterations,\n    address _silo\n  ) external {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (IERC20(collateralAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_NOT_ALLOWED();\n\n    IERC20(collateralAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    _leverage(\n      IBaseLeverageWihtoutFlashloan1.LeverageParams(\n        _principal,\n        _iterations,\n        ISturdyPair(_silo).asset(),\n        collateralAsset,\n        _silo\n      )\n    );\n  }\n\n  /**\n   * @param _principal - The amount of collateral, uint256 max value should withdraw all collateral\n   * @param _slippage - The slippage of the every withdrawal amount. 1% = 100\n   * @param _iterations - Loop count\n   * @param _healthFactor - The heathFactor value to keep after leave position, 1 = 1e18\n   * @param _silo - The silo address\n   */\n  function leavePosition(\n    uint256 _principal,\n    uint256 _slippage,\n    uint256 _iterations,\n    uint256 _healthFactor,\n    address _silo\n  ) external {\n    ISturdyPair pair = ISturdyPair(_silo);\n    address collateralAsset = pair.collateralContract();\n    address borrowAsset = pair.asset();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (borrowAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_healthFactor < 1e18) revert LV_INVALID_CONFIGURATION();\n\n    // reduce leverage to increase healthFactor\n    if (_iterations != 0) {\n      _reduceLeverageWithAmount(_silo, _slippage, 0);\n    } else {\n      _reduceLeverageWithAmount(\n        _silo,\n        _slippage,\n        _principal\n      );\n      return;\n    }\n\n    uint256 count;\n    do {\n      // limit loop count\n      if (count >= _iterations) revert LV_REMOVE_ITERATION_OVER();\n\n      // withdraw collateral keeping the healthFactor\n      uint256 availableAmount = _calcWithdrawalAmount(\n        _silo,\n        _healthFactor\n      );\n      if (availableAmount == 0) break;\n\n      uint256 requiredAmount = _principal - IERC20(collateralAsset).balanceOf(address(this));\n      uint256 removeAmount = Math.min(availableAmount, requiredAmount);\n      _remove(removeAmount, _silo, _slippage, msg.sender);\n\n      if (removeAmount == requiredAmount) break;\n\n      uint256 debtShares = pair.userBorrowShares(msg.sender);\n      uint256 debtAmount =  pair.toBorrowAmount(debtShares, true, true);\n      if (debtAmount != 0) {\n        // swap collateral to borrowing asset\n        // in this case, some collateral asset maybe remained because of convex (ex: sUSD)\n        uint256 borrowingAssetAmount = _swapAsset(_silo, collateralAsset, borrowAsset, IERC20(collateralAsset).balanceOf(address(this)), 0);\n        uint256 repayAmount = Math.min(debtAmount, borrowingAssetAmount);\n        // repay\n        _repay(_silo, repayAmount, msg.sender);\n        if (borrowingAssetAmount > repayAmount) {\n          // swap borrowing asset to collateral in case of extra ramined borrowing asset after repay\n          _swapAsset(_silo, borrowAsset, collateralAsset, IERC20(borrowAsset).balanceOf(address(this)), 0);\n        }\n      }\n\n      count++;\n    } while (true);\n\n    // finally deliver the collateral to user\n    IERC20(collateralAsset).safeTransfer(msg.sender, IERC20(collateralAsset).balanceOf(address(this)));\n  }\n\n  /**\n   * @param _principal - The amount of zapping asset\n   * @param _borrowAmount - The amount of borrowing asset\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _minCollateralAmount - The min amount of collateral asset swapped from zapping asset\n   * @param _silo - The silo address\n   */\n  function zapDeposit(\n    uint256 _principal,\n    uint256 _borrowAmount,\n    uint256 _minCollateralAmount,\n    address _zappingAsset,\n    address _silo\n  ) external nonReentrant {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _silo,\n      _zappingAsset, \n      collateralAsset, \n      _principal,\n      _minCollateralAmount\n    );\n    \n    // deposit collateral\n    _supply(collateralAsset, _silo, collateralAmount, msg.sender);\n\n    //borrow\n    if (_borrowAmount != 0) {\n      _borrow(_silo, _borrowAmount, msg.sender, msg.sender);\n    }\n  }\n\n  /**\n   * @param _principal - The amount of the zapping asset\n   * @param _iterations - Loop count\n   * @param _zappingAsset - The address which will zap into collateral asset\n   * @param _minCollateralAmount - The min amount of collateral asset swapped from zapping asset\n   * @param _silo - The silo address\n   */\n  function zapLeverage(\n    uint256 _principal,\n    uint256 _iterations,\n    uint256 _minCollateralAmount,\n    address _zappingAsset,\n    address _silo\n  ) external nonReentrant {\n    address collateralAsset = ISturdyPair(_silo).collateralContract();\n    if (_principal == 0) revert LV_AMOUNT_NOT_GT_0();\n    if (_zappingAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (collateralAsset == address(0)) revert LV_INVALID_CONFIGURATION();\n    if (IERC20(_zappingAsset).balanceOf(msg.sender) < _principal) revert LV_SUPPLY_FAILED();\n\n    IERC20(_zappingAsset).safeTransferFrom(msg.sender, address(this), _principal);\n\n    uint256 collateralAmount = _swapAsset(\n      _silo,\n      _zappingAsset, \n      collateralAsset, \n      _principal,\n      _minCollateralAmount\n    );\n\n    _leverage(\n      IBaseLeverageWihtoutFlashloan1.LeverageParams(\n        collateralAmount,\n        _iterations,\n        ISturdyPair(_silo).asset(),\n        collateralAsset,\n        _silo\n      )\n    );\n  }\n\n  function _leverage(IBaseLeverageWihtoutFlashloan1.LeverageParams memory _params) internal {\n    uint256 suppliedAmount = _params.principal;\n    uint256 borrowAmount;\n\n    _supply(_params.collateralAsset, _params.silo, suppliedAmount, msg.sender);\n    \n    for (uint256 i; i < _params.iterations; ++i) {\n      borrowAmount = _calcBorrowableAmount(\n        _params.silo,\n        suppliedAmount\n      );\n      if (borrowAmount != 0) {\n        // borrow\n        _borrow(_params.silo, borrowAmount, msg.sender, address(this));\n        // swap borrowing asset to collateral\n        suppliedAmount = _swapAsset(_params.silo, _params.borrowAsset, _params.collateralAsset, borrowAmount, 0);\n        // supply to LP\n        _supply(_params.collateralAsset, _params.silo, suppliedAmount, msg.sender);\n      }\n    }\n  }\n\n  function _reduceLeverageWithAmount(\n    address _silo,\n    uint256 _slippage,\n    uint256 _amount\n  ) internal {\n    // withdraw available collateral\n    ISturdyPair pair = ISturdyPair(_silo);\n    address collateralAsset = pair.collateralContract();\n    address borrowAsset = pair.asset();\n    uint256 requireAmount = _amount;\n\n    do {\n      uint256 debtShares = pair.userBorrowShares(msg.sender);\n      uint256 debtAmount =  pair.toBorrowAmount(debtShares, true, true);\n      if (debtAmount == 0) break;\n\n      uint256 availableAmount = _calcWithdrawalAmount(\n        _silo,\n        HEALTH_FACTOR\n      );\n      uint256 removeAmount = _amount != 0\n        ? Math.min(availableAmount, requireAmount)\n        : availableAmount;\n      _remove(removeAmount, _silo, _slippage, msg.sender);\n\n      // swap collateral to borrowing asset\n      // in this case, some collateral asset maybe remained because of convex (ex: sUSD)\n      uint256 borrowingAssetAmount = _swapAsset(_silo, collateralAsset, borrowAsset, IERC20(collateralAsset).balanceOf(address(this)), 0);\n      uint256 repayAmount = Math.min(debtAmount, borrowingAssetAmount);\n      // repay\n      _repay(_silo, repayAmount, msg.sender);\n      if (borrowingAssetAmount > repayAmount) {\n        // swap borrowing asset to collateral in case of extra ramined borrowing asset after repay\n        uint256 collateralAmount = _swapAsset(\n          _silo,\n          borrowAsset,\n          collateralAsset,\n          IERC20(borrowAsset).balanceOf(address(this)),\n          0\n        );\n        _supply(collateralAsset, _silo, collateralAmount, msg.sender);\n        removeAmount -= collateralAmount;\n      }\n      // one time reduce leverage\n      if (_amount == 0) break;\n\n      requireAmount -= removeAmount;\n      // completed the required amount to reduce leverage\n      if (requireAmount == 0) break;\n    } while (true);\n  }\n\n  function _calcBorrowableAmount(\n    address _silo,\n    uint256 _collateralAmount\n  ) internal virtual returns (uint256);\n\n  function _calcWithdrawalAmount(\n    address _silo,\n    uint256 _healthFactor\n  ) internal virtual returns (uint256);\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal virtual;\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal virtual;\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal virtual;\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal virtual;\n\n  function _swapAsset(\n    address _silo,\n    address _fromAsset,\n    address _toAsset,\n    uint256 _amount,\n    uint256 _minAmountOut\n  ) internal virtual returns (uint256);\n}"
      },
      "contracts/src/leverages/Mode/SturdyLeverageWihtoutFlashloan.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {BaseLeverageWihtoutFlashloan} from \"./BaseLeverageWihtoutFlashloan.sol\";\nimport {IBaseLeverageWihtoutFlashloan} from \"../../interfaces/Mode/IBaseLeverageWihtoutFlashloan.sol\";\nimport {ISturdyPair} from \"../../interfaces/ISturdyPair.sol\";\nimport {ISiloGateway} from \"../../interfaces/ISiloGateway.sol\";\n\ncontract SturdyLeverageWihtoutFlashloan is Ownable, BaseLeverageWihtoutFlashloan {\n  using SafeERC20 for IERC20;\n\n  uint256 private constant SAFE_BUFFER = 5000;\n\n  // silo -> silo gateway\n  mapping (address => address) private _siloToGateway;\n\n  error LV_REPAY_FAILED();\n  error LV_SWAP_FAILED();\n\n  /**\n   * @dev Set the mapping between silos and gateways. \n   *      Gateways will be used to borrow asset for the Just-In-Time liquidity features.\n   * @param _silos - The silo addresses\n   * @param _gateways - The gateway addresses\n   */\n  function setGateways(\n    address[] calldata _silos, \n    address[] calldata _gateways\n  ) external payable onlyOwner {\n    uint256 length = _silos.length;\n    if (length != _gateways.length) revert LV_INVALID_CONFIGURATION();\n\n    for (uint256 i; i < length; ++i) {\n      _siloToGateway[_silos[i]] = _gateways[i];\n    }\n  }\n\n  /**\n   * @dev Get the gateway address for the silo\n   * @param _silo - The silo address\n   * @return The gateway address\n   */\n  function getGateway(\n    address _silo\n  ) external view returns (address) {\n    return _siloToGateway[_silo];\n  }\n\n  function _calcBorrowableAmount(\n    address _silo,\n    uint256 _collateralAmount\n  ) internal override returns (uint256) {\n    ISturdyPair pair = ISturdyPair(_silo);\n\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    uint256 availableBorrowAmount = _collateralAmount * EXCHANGE_PRECISION * pair.maxLTV() / exchangeRate / LTV_PRECISION;\n    \n    return availableBorrowAmount > SAFE_BUFFER ? availableBorrowAmount - SAFE_BUFFER : 0;\n  }\n\n  function _calcWithdrawalAmount(\n    address _silo,\n    uint256 _healthFactor\n  ) internal override returns (uint256) {\n    ISturdyPair pair = ISturdyPair(_silo);\n\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    uint256 debtShares = pair.userBorrowShares(msg.sender);\n    uint256 debtAmount =  pair.toBorrowAmount(debtShares, true, true);\n    uint256 collateralAmount = pair.userCollateralBalance(msg.sender);\n    uint256 withdrawalAmount = collateralAmount - debtAmount * _healthFactor * exchangeRate * LTV_PRECISION / pair.maxLTV() / EXCHANGE_PRECISION / 1e18;\n\n    return withdrawalAmount;\n  }\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal override {\n    IERC20(_collateralAsset).safeApprove(_silo, 0);\n    IERC20(_collateralAsset).safeApprove(_silo, _amount);\n    ISturdyPair(_silo).addCollateral(_amount, _user);\n  }\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal override {\n    ISturdyPair(_silo).removeCollateralFrom(_amount, address(this), _user);\n  }\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal override {\n    if (_siloToGateway[_silo] == address(0)) {\n      ISturdyPair(_silo).borrowAssetOnBehalfOf(_amount, _borrower);\n      \n      if (_receiver != address(this)) {\n        IERC20(ISturdyPair(_silo).asset()).safeTransfer(_receiver, _amount);\n      }\n    } else {\n      ISiloGateway(_siloToGateway[_silo]).borrowAsset(\n        _silo,\n        _amount,\n        0,\n        ISturdyPair(_silo).collateralContract(),\n        _borrower,\n        _receiver\n      );\n    }\n  }\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal override {\n    IERC20 borrowAsset = IERC20(ISturdyPair(_silo).asset());\n\n    ISturdyPair(_silo).addInterest(false);\n\n    uint256 borrowShares =  ISturdyPair(_silo).toBorrowShares(_amount, false, false);\n\n    borrowAsset.safeApprove(_silo, 0);\n    borrowAsset.safeApprove(_silo, _amount);\n\n    uint256 paybackAmount = ISturdyPair(_silo).repayAsset(borrowShares, _borrower);\n    if (paybackAmount == 0) revert LV_REPAY_FAILED();\n  }\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverageWihtoutFlashloan.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal virtual override returns (uint256) {\n    return _swapByPath(_amount, _path, _checkOutAmount);\n  }\n}"
      },
      "contracts/src/leverages/Mode/SturdyLeverageWihtoutFlashloan1.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {BaseLeverageWihtoutFlashloan1} from \"./BaseLeverageWihtoutFlashloan1.sol\";\nimport {IBaseLeverageWihtoutFlashloan1} from \"../../interfaces/Mode/IBaseLeverageWihtoutFlashloan1.sol\";\nimport {ISturdyPair} from \"../../interfaces/ISturdyPair.sol\";\nimport {ISiloGateway} from \"../../interfaces/ISiloGateway.sol\";\nimport {IKimRouter} from \"../../interfaces/Mode/Kim/IKimRouter.sol\";\n\ncontract SturdyLeverageWihtoutFlashloan1 is Ownable, BaseLeverageWihtoutFlashloan1 {\n  using SafeERC20 for IERC20;\n\n  uint256 private constant SAFE_BUFFER = 5000;\n  uint256 private constant PERCENTAGE_FACTOR = 100_00;\n  address private constant WETH = 0x4200000000000000000000000000000000000006;\n  \n  address public constant SWAP_ROUTER = 0x5D61c537393cf21893BE619E36fC94cd73C77DD3;\n\n  // silo -> silo gateway\n  mapping (address => address) private _siloToGateway;\n  // swap slippage\n  uint256 private _swapSlippage;\n\n  error LV_REPAY_FAILED();\n  error LV_SWAP_FAILED();\n\n  /**\n   * @dev Set the mapping between silos and gateways. \n   *      Gateways will be used to borrow asset for the Just-In-Time liquidity features.\n   * @param _silos - The silo addresses\n   * @param _gateways - The gateway addresses\n   */\n  function setGateways(\n    address[] calldata _silos, \n    address[] calldata _gateways\n  ) external payable onlyOwner {\n    uint256 length = _silos.length;\n    if (length != _gateways.length) revert LV_INVALID_CONFIGURATION();\n\n    for (uint256 i; i < length; ++i) {\n      _siloToGateway[_silos[i]] = _gateways[i];\n    }\n  }\n\n  /**\n   * @dev Set the swap slippage value \n   * @param _slippage - The silo percent value. 1% = 100\n   */\n  function setSwapSlippage(\n    uint256 _slippage\n  ) external payable onlyOwner {\n    _swapSlippage = _slippage;\n  }\n\n  /**\n   * @dev Get the gateway address for the silo\n   * @param _silo - The silo address\n   * @return The gateway address\n   */\n  function getGateway(\n    address _silo\n  ) external view returns (address) {\n    return _siloToGateway[_silo];\n  }\n\n  /**\n   * @dev Get the swap slippage value\n   * @return The slippage value\n   */\n  function getSwapSlippage() external view returns (uint256) {\n    return _swapSlippage;\n  }\n\n  function _calcBorrowableAmount(\n    address _silo,\n    uint256 _collateralAmount\n  ) internal override returns (uint256) {\n    ISturdyPair pair = ISturdyPair(_silo);\n\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    uint256 availableBorrowAmount = _collateralAmount * EXCHANGE_PRECISION * pair.maxLTV() / exchangeRate / LTV_PRECISION;\n    \n    return availableBorrowAmount > SAFE_BUFFER ? availableBorrowAmount - SAFE_BUFFER : 0;\n  }\n\n  function _calcWithdrawalAmount(\n    address _silo,\n    uint256 _healthFactor\n  ) internal override returns (uint256) {\n    ISturdyPair pair = ISturdyPair(_silo);\n\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    uint256 debtShares = pair.userBorrowShares(msg.sender);\n    uint256 debtAmount =  pair.toBorrowAmount(debtShares, true, true);\n    uint256 collateralAmount = pair.userCollateralBalance(msg.sender);\n    uint256 withdrawalAmount = collateralAmount - debtAmount * _healthFactor * exchangeRate * LTV_PRECISION / pair.maxLTV() / EXCHANGE_PRECISION / 1e18;\n\n    return withdrawalAmount;\n  }\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal override {\n    IERC20(_collateralAsset).safeApprove(_silo, 0);\n    IERC20(_collateralAsset).safeApprove(_silo, _amount);\n    ISturdyPair(_silo).addCollateral(_amount, _user);\n  }\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal override {\n    ISturdyPair(_silo).removeCollateralFrom(_amount, address(this), _user);\n  }\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal override {\n    if (_siloToGateway[_silo] == address(0)) {\n      ISturdyPair(_silo).borrowAssetOnBehalfOf(_amount, _borrower);\n      \n      if (_receiver != address(this)) {\n        IERC20(ISturdyPair(_silo).asset()).safeTransfer(_receiver, _amount);\n      }\n    } else {\n      ISiloGateway(_siloToGateway[_silo]).borrowAsset(\n        _silo,\n        _amount,\n        0,\n        ISturdyPair(_silo).collateralContract(),\n        _borrower,\n        _receiver\n      );\n    }\n  }\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal override {\n    IERC20 borrowAsset = IERC20(ISturdyPair(_silo).asset());\n\n    ISturdyPair(_silo).addInterest(false);\n\n    uint256 borrowShares =  ISturdyPair(_silo).toBorrowShares(_amount, false, false);\n\n    borrowAsset.safeApprove(_silo, 0);\n    borrowAsset.safeApprove(_silo, _amount);\n\n    uint256 paybackAmount = ISturdyPair(_silo).repayAsset(borrowShares, _borrower);\n    if (paybackAmount == 0) revert LV_REPAY_FAILED();\n  }\n\n  function _swapAsset(\n    address _silo,\n    address _fromAsset,\n    address _toAsset,\n    uint256 _amount,\n    uint256 _minAmountOut\n  ) internal override returns (uint256) {\n    ISturdyPair pair = ISturdyPair(_silo);\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    (,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    uint256 prevBalance = IERC20(_toAsset).balanceOf(address(this));\n    uint256 minAmountOut;\n\n    if (_fromAsset == pair.asset()) {\n      // borrowAsset -> collateralAsset\n      minAmountOut = _amount * exchangeRate * (PERCENTAGE_FACTOR - _swapSlippage) / EXCHANGE_PRECISION / PERCENTAGE_FACTOR;\n    } else if (_toAsset == pair.asset()) {\n      // collateralAsset -> borrowAsset\n      minAmountOut = _amount * EXCHANGE_PRECISION * (PERCENTAGE_FACTOR - _swapSlippage) / exchangeRate / PERCENTAGE_FACTOR;\n    } else {\n      // zapAsset -> collateralAsset\n      minAmountOut = _minAmountOut;\n    }\n\n    address[] memory path;\n    if (_fromAsset == WETH || _toAsset == WETH) {\n      path = new address[](2);\n      path[0] = _fromAsset;\n      path[1] = _toAsset;\n    } else {\n      path = new address[](3);\n      path[0] = _fromAsset;\n      path[1] = WETH;\n      path[2] = _toAsset;\n    }\n\n    IERC20(_fromAsset).safeApprove(SWAP_ROUTER, 0);\n    IERC20(_fromAsset).safeApprove(SWAP_ROUTER, _amount);\n\n    IKimRouter(SWAP_ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(\n      _amount, \n      minAmountOut, \n      path, \n      address(this), \n      address(this), \n      block.timestamp\n    );\n\n    return IERC20(_toAsset).balanceOf(address(this)) - prevBalance;\n  }\n}"
      },
      "contracts/src/leverages/PendlePTLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {SturdyLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./SturdyLeverage.sol\";\nimport {IPendleMarket} from \"../interfaces/Pendle/IPendleMarket.sol\";\nimport {IPendleRouter} from \"../interfaces/Pendle/IPendleRouter.sol\";\nimport {ISY} from \"../interfaces/Pendle/ISY.sol\";\nimport {IERC4626} from \"../interfaces/IERC4626.sol\";\n\n/// @notice  Leverage contract for pendle pt token\ncontract PendlePTLeverage is SturdyLeverage {\n  using SafeERC20 for IERC20;\n\n  address private constant PENDLE_ROUTER = 0x00000000005BBB0EF59571E58418F9a4357b68A0;\n\n  address public immutable PENDLE_MARKET;\n\n  IPendleRouter.ApproxParams public routerParams;\n\n  // pendle PT -> pendle Market(LPT)\n  mapping (address => address) public ptToMarket;\n\n  error LV_REQUIRE_MIN_AMOUNT();\n\n  constructor() {\n    routerParams.guessMin = 0;\n    routerParams.guessMax = type(uint256).max;\n    routerParams.guessOffchain = 0; // strictly 0\n    routerParams.maxIteration = 256;\n    routerParams.eps = 1e15; // max 0.1% unused\n  }\n\n  /**\n   * @dev Set the mapping between PT and Market. \n   * @param _pts - The pendle PT token addresses\n   * @param _markets - The pendle Market addresses\n   */\n  function setPTAndMarket(\n    address[] calldata _pts, \n    address[] calldata _markets\n  ) external payable onlyOwner {\n    uint256 length = _pts.length;\n    if (length != _markets.length) revert LV_INVALID_CONFIGURATION();\n\n    for (uint256 i; i < length; ++i) {\n      ptToMarket[_pts[i]] = _markets[i];\n    }\n  }\n\n  /**\n    * @notice Set the routerParams for the pendleRouter. Pendle's AMM only supports the built-in swapSyForExactPt. To execute a swapExactSyForPt, the router will conduct a binary search to determine the amount of PT to swap.\n    * @param _guessMin The minimum value for binary search. Default: 0.\n    * @param _guessMax The maximum value for binary search. Default: type(uint256).max.\n    * @param _maxIteration The maximum number of times binary search will be performed. Default: 256.\n    * @param _eps The precision of binary search - the maximum proportion of the input that can be unused. Default: 1e15 == max 0.1% unused. Alternatively: 1e14 implies that no more than 0.01% unused.     \n    */\n  function setRouterParams(uint256 _guessMin, uint256 _guessMax, uint256 _maxIteration, uint256 _eps) external onlyOwner {\n      routerParams.guessMin = _guessMin; // default: 0\n      routerParams.guessMax = _guessMax; // default: type(uint256).max\n      routerParams.maxIteration = _maxIteration; // default: 256\n      routerParams.eps = _eps; // default: 1e15 == max 0.1% unused. Alternatively: 1e14 implies that no more than 0.01% unused.\n  }\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal override returns (uint256) {\n    if (_path.swapType > IBaseLeverage.SwapType.WITHDRAW) {\n      return _swapByPath(_amount, _path, _checkOutAmount);\n    }\n\n    uint256 outAmount;\n    address market;\n    address asset;\n\n    if (_path.swapType == IBaseLeverage.SwapType.UNSTAKE) {\n      // ERC4626_VAULT_LP -> asset\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n\n      // Withdraw from ERC4626 Vault and receive asset\n      outAmount = IERC4626(_path.swapFrom).redeem(_amount, address(this), address(this));\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    } else if (_path.swapType == IBaseLeverage.SwapType.STAKE) {\n      // asset -> ERC4626_VAULT_LP\n      // Deposit asset to ERC4626 Vault and receive LP token\n      address vault = _path.swapTo;\n      asset = _path.swapFrom;\n      IERC20(asset).safeApprove(vault, 0);\n      IERC20(asset).safeApprove(vault, _amount);\n      outAmount = IERC4626(vault).deposit(_amount, address(this));\n    } else if (_path.swapType == IBaseLeverage.SwapType.WITHDRAW) {\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n      \n      address PT = _path.swapFrom;\n      asset = _path.swapTo;\n      market = ptToMarket[PT];\n      (address SY,,) = IPendleMarket(market).readTokens();\n      \n      //Pendle PT --> SY\n      IERC20(PT).safeApprove(PENDLE_ROUTER, 0);\n      IERC20(PT).safeApprove(PENDLE_ROUTER, _amount);\n\n      IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address\n      (outAmount,) = IPendleRouter(PENDLE_ROUTER).swapExactPtForSy(address(this), market, _amount, 0, limit);\n\n      //SY --> asset\n      if (outAmount != 0) {\n        outAmount = ISY(SY).redeem(address(this), outAmount, asset, 0, false);\n      }\n\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    } else if (_path.swapType == IBaseLeverage.SwapType.DEPOSIT) {\n      asset = _path.swapFrom;\n      market = ptToMarket[_path.swapTo];\n      (address SY,,) = IPendleMarket(market).readTokens();\n      \n      //asset --> SY\n      IERC20(asset).safeApprove(SY, 0);\n      IERC20(asset).safeApprove(SY, _amount);\n      outAmount = ISY(SY).deposit(address(this), asset, _amount, 0);\n      \n      //SY --> Pendle PT\n      if (outAmount != 0) {\n        IERC20(SY).safeApprove(PENDLE_ROUTER, 0);\n        IERC20(SY).safeApprove(PENDLE_ROUTER, outAmount);\n\n        IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address\n        (outAmount,) = IPendleRouter(PENDLE_ROUTER).swapExactSyForPt(address(this), market, outAmount, 0, routerParams, limit);\n      }\n    }\n\n    if (_checkOutAmount && outAmount < _path.outAmount) {\n      revert LV_REQUIRE_MIN_AMOUNT();\n    }\n  \n    return outAmount;\n  }\n}"
      },
      "contracts/src/leverages/SturdyLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {BaseLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./BaseLeverage.sol\";\nimport {ISturdyPair} from \"../interfaces/ISturdyPair.sol\";\nimport {ISiloGateway} from \"../interfaces/ISiloGateway.sol\";\n\ncontract SturdyLeverage is Ownable, BaseLeverage {\n  using SafeERC20 for IERC20;\n\n  // silo -> silo gateway\n  mapping (address => address) private _siloToGateway;\n\n  error LV_REPAY_FAILED();\n\n  /**\n   * @dev Set the mapping between silos and gateways. \n   *      Gateways will be used to borrow asset for the Just-In-Time liquidity features.\n   * @param _silos - The silo addresses\n   * @param _gateways - The gateway addresses\n   */\n  function setGateways(\n    address[] calldata _silos, \n    address[] calldata _gateways\n  ) external payable onlyOwner {\n    uint256 length = _silos.length;\n    if (length != _gateways.length) revert LV_INVALID_CONFIGURATION();\n\n    for (uint256 i; i < length; ++i) {\n      _siloToGateway[_silos[i]] = _gateways[i];\n    }\n  }\n\n  /**\n   * @dev Get the gateway address for the silo\n   * @param _silo - The silo address\n   * @return The gateway address\n   */\n  function getGateway(\n    address _silo\n  ) external view returns (address) {\n    return _siloToGateway[_silo];\n  }\n\n  function _enterPositionWithFlashloan(\n    address _borrowAsset,\n    uint256 _borrowedAmount,\n    uint256 _fee,\n    IBaseLeverage.FlashLoanParams memory _params\n  ) internal override {\n    //swap borrow asset -> collateral\n    _swapAsset(\n      _borrowAsset,\n      _params.collateralAsset,\n      _borrowedAmount,\n      _params.borrowAssetAndCollateral.paths,\n      _params.borrowAssetAndCollateral.pathLength,\n      true\n    );\n\n    uint256 collateralAmount = IERC20(_params.collateralAsset).balanceOf(address(this));\n    if (collateralAmount < _params.minRequiredAmount) revert LV_SUPPLY_FAILED();\n\n    //deposit collateral\n    _supply(_params.collateralAsset, _params.silo, collateralAmount, _params.user);\n\n    ISturdyPair pair = ISturdyPair(_params.silo);\n    if (pair.asset() == _borrowAsset) {\n      //borrow\n      _borrow(_params.silo, _borrowedAmount + _fee, _params.user, address(this));\n    } else {\n      ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n      pair.addInterest(false);\n\n      (,, uint256 exchangeRate) = pair.updateExchangeRate();\n      uint256 borrowShares = pair.userBorrowShares(_params.user);\n      uint256 borrowAmount =  pair.toBorrowAmount(borrowShares, true, false);\n      uint256 collateralAmount = pair.userCollateralBalance(_params.user);\n      borrowAmount = collateralAmount * EXCHANGE_PRECISION * pair.maxLTV() / exchangeRate / LTV_PRECISION - borrowAmount;\n\n      //borrow\n      _borrow(_params.silo, borrowAmount, _params.user, address(this));\n\n      //swap asset -> borrow asset\n      _swapAsset(\n        pair.asset(),\n        _borrowAsset,\n        borrowAmount,\n        _params.borrowAssetAndSiloAsset.reversePaths,\n        _params.borrowAssetAndSiloAsset.pathLength,\n        true\n      );\n    }\n  }\n\n  function _afterLeverageWithFlashloan(\n    address _borrowAsset,\n    IBaseLeverage.LeverageParams memory _params\n  ) internal override {\n    address asset = ISturdyPair(_params.silo).asset();\n\n    if (asset == _borrowAsset) return;\n\n    // remained borrow asset -> asset\n    _swapAsset(\n      _borrowAsset,\n      asset,\n      IERC20(_borrowAsset).balanceOf(address(this)),\n      _params.borrowAssetAndSiloAsset.paths,\n      _params.borrowAssetAndSiloAsset.pathLength,\n      false\n    );\n\n    // repay\n    _repay(_params.silo, IERC20(asset).balanceOf(address(this)), _params.user);\n  }\n\n  function _withdrawWithFlashloan(\n    address _borrowAsset,\n    uint256 _borrowedAmount,\n    IBaseLeverage.FlashLoanParams memory _params\n  ) internal override {\n    ISturdyPair pair = ISturdyPair(_params.silo);\n    address asset = pair.asset();\n\n    if (asset == _borrowAsset) {\n      // repay\n      _repay(_params.silo, _borrowedAmount, _params.user);\n    } else {\n      //swap borrow asset -> asset\n      _swapAsset(\n        _borrowAsset,\n        asset,\n        _borrowedAmount,\n        _params.borrowAssetAndSiloAsset.paths,\n        _params.borrowAssetAndSiloAsset.pathLength,\n        true\n      );\n\n      uint256 assetAmount = IERC20(asset).balanceOf(address(this));\n      if (assetAmount < _params.minRequiredAmount) revert LV_REPAY_FAILED();\n\n      // repay\n      _repay(_params.silo, _params.minRequiredAmount, _params.user);\n\n      //swap asset -> borrow asset\n      _swapAsset(\n        asset,\n        _borrowAsset,\n        assetAmount - _params.minRequiredAmount,\n        _params.borrowAssetAndSiloAsset.reversePaths,\n        _params.borrowAssetAndSiloAsset.pathLength,\n        false\n      );\n    }\n\n    // withdraw collateral    \n    if (_params.collateralAsset != pair.collateralContract()) revert LV_INVALID_CONFIGURATION();\n\n    ( uint256 LTV_PRECISION,,,, uint256 EXCHANGE_PRECISION,,,) = pair.getConstants();\n    pair.addInterest(false);\n\n    (,, uint256 exchangeRate) = pair.updateExchangeRate();\n    uint256 borrowShares = pair.userBorrowShares(_params.user);\n    uint256 borrowAmount =  pair.toBorrowAmount(borrowShares, true, false);\n    uint256 collateralAmount = pair.userCollateralBalance(_params.user);\n    uint256 withdrawalAmount = collateralAmount - (borrowAmount * exchangeRate * LTV_PRECISION / EXCHANGE_PRECISION / pair.maxLTV());\n\n    _remove(withdrawalAmount, _params.silo, 0, _params.user);\n\n    // collateral -> borrow asset\n    _swapAsset(\n      _params.collateralAsset, \n      _borrowAsset, \n      IERC20(_params.collateralAsset).balanceOf(address(this)),\n      _params.borrowAssetAndCollateral.reversePaths, \n      _params.borrowAssetAndCollateral.pathLength,\n      true\n    );\n  }\n\n  function _supply(\n    address _collateralAsset, \n    address _silo, \n    uint256 _amount, \n    address _user\n  ) internal override {\n    IERC20(_collateralAsset).safeApprove(_silo, 0);\n    IERC20(_collateralAsset).safeApprove(_silo, _amount);\n    ISturdyPair(_silo).addCollateral(_amount, _user);\n  }\n\n  function _remove(\n    uint256 _amount, \n    address _silo, \n    uint256 _slippage, \n    address _user\n  ) internal override {\n    ISturdyPair(_silo).removeCollateralFrom(_amount, address(this), _user);\n  }\n\n  function _borrow(\n    address _silo, \n    uint256 _amount, \n    address _borrower,\n    address _receiver\n  ) internal override {\n    if (_siloToGateway[_silo] == address(0)) {\n      ISturdyPair(_silo).borrowAssetOnBehalfOf(_amount, _borrower);\n      \n      if (_receiver != address(this)) {\n        IERC20(ISturdyPair(_silo).asset()).safeTransfer(_receiver, _amount);\n      }\n    } else {\n      ISiloGateway(_siloToGateway[_silo]).borrowAsset(\n        _silo,\n        _amount,\n        0,\n        ISturdyPair(_silo).collateralContract(),\n        _borrower,\n        _receiver\n      );\n    }\n\n    \n  }\n\n  function _repay(\n    address _silo, \n    uint256 _amount, \n    address _borrower\n  ) internal override {\n    IERC20 borrowAsset = IERC20(ISturdyPair(_silo).asset());\n\n    ISturdyPair(_silo).addInterest(false);\n\n    uint256 borrowShares =  ISturdyPair(_silo).toBorrowShares(_amount, false, false);\n\n    borrowAsset.safeApprove(_silo, 0);\n    borrowAsset.safeApprove(_silo, _amount);\n\n    uint256 paybackAmount = ISturdyPair(_silo).repayAsset(borrowShares, _borrower);\n    if (paybackAmount == 0) revert LV_REPAY_FAILED();\n  }\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal virtual override returns (uint256) {\n    return _swapByPath(_amount, _path, _checkOutAmount);\n  }\n}"
      },
      "contracts/src/leverages/YearnVaultPendleLPTLeverage.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {SturdyLeverage, IBaseLeverage, IERC20, SafeERC20} from \"./SturdyLeverage.sol\";\nimport {IYearnVault} from \"../interfaces/Yearn/IYearnVault.sol\";\nimport {IPendleMarket} from \"../interfaces/Pendle/IPendleMarket.sol\";\nimport {IPendleRouter} from \"../interfaces/Pendle/IPendleRouter.sol\";\nimport {ISY} from \"../interfaces/Pendle/ISY.sol\";\n\n/// @notice  Leverage contract for yearn vault of pendle lp token\ncontract YearnVaultPendleLPTLeverage is SturdyLeverage {\n  using SafeERC20 for IERC20;\n\n  address private constant PENDLE_ROUTER = 0x00000000005BBB0EF59571E58418F9a4357b68A0;\n\n  address public immutable YEARN_VAULT;\n  IPendleRouter.ApproxParams public routerParams;\n\n  error LV_REQUIRE_MIN_AMOUNT();\n\n  constructor(\n    address _yearnVault\n  ) {\n    YEARN_VAULT = _yearnVault;\n\n    routerParams.guessMin = 0;\n    routerParams.guessMax = type(uint256).max;\n    routerParams.guessOffchain = 0; // strictly 0\n    routerParams.maxIteration = 256;\n    routerParams.eps = 1e15; // max 0.1% unused\n  }\n\n  /**\n    * @notice Set the routerParams for the pendleRouter. Pendle's AMM only supports the built-in swapSyForExactPt. To execute a swapExactSyForPt, the router will conduct a binary search to determine the amount of PT to swap.\n    * @param _guessMin The minimum value for binary search. Default: 0.\n    * @param _guessMax The maximum value for binary search. Default: type(uint256).max.\n    * @param _maxIteration The maximum number of times binary search will be performed. Default: 256.\n    * @param _eps The precision of binary search - the maximum proportion of the input that can be unused. Default: 1e15 == max 0.1% unused. Alternatively: 1e14 implies that no more than 0.01% unused.     \n    */\n  function setRouterParams(uint256 _guessMin, uint256 _guessMax, uint256 _maxIteration, uint256 _eps) external onlyOwner {\n      routerParams.guessMin = _guessMin; // default: 0\n      routerParams.guessMax = _guessMax; // default: type(uint256).max\n      routerParams.maxIteration = _maxIteration; // default: 256\n      routerParams.eps = _eps; // default: 1e15 == max 0.1% unused. Alternatively: 1e14 implies that no more than 0.01% unused.\n  }\n\n  function _processSwap(\n    uint256 _amount,\n    IBaseLeverage.MultipSwapPath memory _path,\n    bool _checkOutAmount\n  ) internal override returns (uint256) {\n    if (_path.swapType > IBaseLeverage.SwapType.WITHDRAW) {\n      return _swapByPath(_amount, _path, _checkOutAmount);\n    }\n\n    address asset;\n    address vault;\n    uint256 outAmount;\n\n    if (_path.swapType == IBaseLeverage.SwapType.WITHDRAW) {\n      if (!_checkOutAmount) revert LV_INVALID_CONFIGURATION();\n      \n      vault = _path.swapFrom;\n      if(vault == YEARN_VAULT) {\n        // Withdraw from Yearn Vault and receive Pendle LP token\n        outAmount = IYearnVault(vault).withdraw(_amount, address(this), 1);\n      } else {\n        // Withdraw from Pendle Pool and receive asset\n        (address SY,,) = IPendleMarket(vault).readTokens();\n\n        //Pendle LP --> SY\n        IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address\n        (outAmount,) = IPendleRouter(PENDLE_ROUTER).removeLiquiditySingleSy(address(this), vault, _amount, 0, limit);\n\n        //SY --> asset\n        outAmount = ISY(SY).redeem(address(this), outAmount, asset, 0, true);\n      }\n      if (outAmount < _path.outAmount) revert LV_REQUIRE_MIN_AMOUNT();\n\n      return outAmount;\n    }\n\n    asset = _path.swapFrom;\n    vault = _path.swapTo;\n\n    if (vault == YEARN_VAULT) {\n      // Deposit Pendle LP token to Yearn Vault and receive Yearn Vault LP token\n      IERC20(asset).safeApprove(vault, 0);\n      IERC20(asset).safeApprove(vault, _amount);\n      outAmount = IYearnVault(vault).deposit(_amount, address(this));\n    } else {\n      // Deposit asset to Pendle pool and receive Pendle LP token.\n      (address SY,,) = IPendleMarket(vault).readTokens();\n      \n      //asset --> SY\n      IERC20(asset).safeApprove(SY, 0);\n      IERC20(asset).safeApprove(SY, _amount);\n      outAmount = ISY(SY).deposit(address(this), asset, _amount, 0);\n      \n      //SY --> Pendle LP\n      if (outAmount > 0) {\n        IERC20(SY).safeApprove(PENDLE_ROUTER, 0);\n        IERC20(SY).safeApprove(PENDLE_ROUTER, outAmount);\n        \n        IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address\n        (outAmount,) = IPendleRouter(PENDLE_ROUTER).addLiquiditySingleSy(address(this), vault, outAmount, 0, routerParams, limit);\n      }\n    }    \n\n    if (_checkOutAmount && outAmount < _path.outAmount) {\n      revert LV_REQUIRE_MIN_AMOUNT();\n    }\n  \n    return outAmount;\n  }\n}"
      },
      "contracts/src/libraries/Aave/DataTypesV3.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nlibrary DataTypesV3 {\n    struct ReserveData {\n        //stores the reserve configuration\n        ReserveConfigurationMap configuration;\n        //the liquidity index. Expressed in ray\n        uint128 liquidityIndex;\n        //the current supply rate. Expressed in ray\n        uint128 currentLiquidityRate;\n        //variable borrow index. Expressed in ray\n        uint128 variableBorrowIndex;\n        //the current variable borrow rate. Expressed in ray\n        uint128 currentVariableBorrowRate;\n        //the current stable borrow rate. Expressed in ray\n        uint128 currentStableBorrowRate;\n        //timestamp of last update\n        uint40 lastUpdateTimestamp;\n        //the id of the reserve. Represents the position in the list of the active reserves\n        uint16 id;\n        //aToken address\n        address aTokenAddress;\n        //stableDebtToken address\n        address stableDebtTokenAddress;\n        //variableDebtToken address\n        address variableDebtTokenAddress;\n        //address of the interest rate strategy\n        address interestRateStrategyAddress;\n        //the current treasury balance, scaled\n        uint128 accruedToTreasury;\n        //the outstanding unbacked aTokens minted through the bridging feature\n        uint128 unbacked;\n        //the outstanding debt borrowed against this asset in isolation mode\n        uint128 isolationModeTotalDebt;\n    }\n\n    struct ReserveConfigurationMap {\n        //bit 0-15: LTV\n        //bit 16-31: Liq. threshold\n        //bit 32-47: Liq. bonus\n        //bit 48-55: Decimals\n        //bit 56: reserve is active\n        //bit 57: reserve is frozen\n        //bit 58: borrowing is enabled\n        //bit 59: stable rate borrowing enabled\n        //bit 60: asset is paused\n        //bit 61: borrowing in isolation mode is enabled\n        //bit 62-63: reserved\n        //bit 64-79: reserve factor\n        //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap\n        //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap\n        //bit 152-167 liquidation protocol fee\n        //bit 168-175 eMode category\n        //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled\n        //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals\n        //bit 252-255 unused\n\n        uint256 data;\n    }\n\n    struct UserConfigurationMap {\n        /**\n         * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.\n         * The first bit indicates if an asset is used as collateral by the user, the second whether an\n         * asset is borrowed by the user.\n         */\n        uint256 data;\n    }\n\n    struct EModeCategory {\n        // each eMode category has a custom ltv and liquidation threshold\n        uint16 ltv;\n        uint16 liquidationThreshold;\n        uint16 liquidationBonus;\n        // each eMode category may or may not have a custom oracle to override the individual assets price oracles\n        address priceSource;\n        string label;\n    }\n\n    enum InterestRateMode {\n        NONE,\n        STABLE,\n        VARIABLE\n    }\n\n    struct ReserveCache {\n        uint256 currScaledVariableDebt;\n        uint256 nextScaledVariableDebt;\n        uint256 currPrincipalStableDebt;\n        uint256 currAvgStableBorrowRate;\n        uint256 currTotalStableDebt;\n        uint256 nextAvgStableBorrowRate;\n        uint256 nextTotalStableDebt;\n        uint256 currLiquidityIndex;\n        uint256 nextLiquidityIndex;\n        uint256 currVariableBorrowIndex;\n        uint256 nextVariableBorrowIndex;\n        uint256 currLiquidityRate;\n        uint256 currVariableBorrowRate;\n        uint256 reserveFactor;\n        ReserveConfigurationMap reserveConfiguration;\n        address aTokenAddress;\n        address stableDebtTokenAddress;\n        address variableDebtTokenAddress;\n        uint40 reserveLastUpdateTimestamp;\n        uint40 stableDebtLastUpdateTimestamp;\n    }\n\n    struct ExecuteLiquidationCallParams {\n        uint256 reservesCount;\n        uint256 debtToCover;\n        address collateralAsset;\n        address debtAsset;\n        address user;\n        bool receiveAToken;\n        address priceOracle;\n        uint8 userEModeCategory;\n        address priceOracleSentinel;\n    }\n\n    struct ExecuteSupplyParams {\n        address asset;\n        uint256 amount;\n        address onBehalfOf;\n        uint16 referralCode;\n    }\n\n    struct ExecuteBorrowParams {\n        address asset;\n        address user;\n        address onBehalfOf;\n        uint256 amount;\n        InterestRateMode interestRateMode;\n        uint16 referralCode;\n        bool releaseUnderlying;\n        uint256 maxStableRateBorrowSizePercent;\n        uint256 reservesCount;\n        address oracle;\n        uint8 userEModeCategory;\n        address priceOracleSentinel;\n    }\n\n    struct ExecuteRepayParams {\n        address asset;\n        uint256 amount;\n        InterestRateMode interestRateMode;\n        address onBehalfOf;\n        bool useATokens;\n    }\n\n    struct ExecuteWithdrawParams {\n        address asset;\n        uint256 amount;\n        address to;\n        uint256 reservesCount;\n        address oracle;\n        uint8 userEModeCategory;\n    }\n\n    struct ExecuteSetUserEModeParams {\n        uint256 reservesCount;\n        address oracle;\n        uint8 categoryId;\n    }\n\n    struct FinalizeTransferParams {\n        address asset;\n        address from;\n        address to;\n        uint256 amount;\n        uint256 balanceFromBefore;\n        uint256 balanceToBefore;\n        uint256 reservesCount;\n        address oracle;\n        uint8 fromEModeCategory;\n    }\n\n    struct FlashloanParams {\n        address receiverAddress;\n        address[] assets;\n        uint256[] amounts;\n        uint256[] interestRateModes;\n        address onBehalfOf;\n        bytes params;\n        uint16 referralCode;\n        uint256 flashLoanPremiumToProtocol;\n        uint256 flashLoanPremiumTotal;\n        uint256 maxStableRateBorrowSizePercent;\n        uint256 reservesCount;\n        address addressesProvider;\n        uint8 userEModeCategory;\n        bool isAuthorizedFlashBorrower;\n    }\n\n    struct FlashloanSimpleParams {\n        address receiverAddress;\n        address asset;\n        uint256 amount;\n        bytes params;\n        uint16 referralCode;\n        uint256 flashLoanPremiumToProtocol;\n        uint256 flashLoanPremiumTotal;\n    }\n\n    struct FlashLoanRepaymentParams {\n        uint256 amount;\n        uint256 totalPremium;\n        uint256 flashLoanPremiumToProtocol;\n        address asset;\n        address receiverAddress;\n        uint16 referralCode;\n    }\n\n    struct CalculateUserAccountDataParams {\n        UserConfigurationMap userConfig;\n        uint256 reservesCount;\n        address user;\n        address oracle;\n        uint8 userEModeCategory;\n    }\n\n    struct ValidateBorrowParams {\n        ReserveCache reserveCache;\n        UserConfigurationMap userConfig;\n        address asset;\n        address userAddress;\n        uint256 amount;\n        InterestRateMode interestRateMode;\n        uint256 maxStableLoanPercent;\n        uint256 reservesCount;\n        address oracle;\n        uint8 userEModeCategory;\n        address priceOracleSentinel;\n        bool isolationModeActive;\n        address isolationModeCollateralAddress;\n        uint256 isolationModeDebtCeiling;\n    }\n\n    struct ValidateLiquidationCallParams {\n        ReserveCache debtReserveCache;\n        uint256 totalDebt;\n        uint256 healthFactor;\n        address priceOracleSentinel;\n    }\n\n    struct CalculateInterestRatesParams {\n        uint256 unbacked;\n        uint256 liquidityAdded;\n        uint256 liquidityTaken;\n        uint256 totalStableDebt;\n        uint256 totalVariableDebt;\n        uint256 averageStableBorrowRate;\n        uint256 reserveFactor;\n        address reserve;\n        address aToken;\n    }\n\n    struct InitReserveParams {\n        address asset;\n        address aTokenAddress;\n        address stableDebtAddress;\n        address variableDebtAddress;\n        address interestRateStrategyAddress;\n        uint16 reservesCount;\n        uint16 maxNumberReserves;\n    }\n}\n"
      },
      "contracts/src/libraries/Aave/ReserveConfiguration.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {DataTypesV3} from \"./DataTypesV3.sol\";\n\n/**\n * @title ReserveConfiguration library\n * @author Aave\n * @notice Implements the bitmap logic to handle the reserve configuration\n */\nlibrary ReserveConfiguration {\n    uint256 internal constant LIQUIDATION_THRESHOLD_MASK =     0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF; // prettier-ignore\n    uint256 internal constant DECIMALS_MASK =                  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant ACTIVE_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant FROZEN_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant BORROWING_MASK =                 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant STABLE_BORROWING_MASK =          0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant PAUSED_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant RESERVE_FACTOR_MASK =            0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant SUPPLY_CAP_MASK =                0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore\n    uint256 internal constant EMODE_CATEGORY_MASK =            0xFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore\n\n    /// @dev For the LTV, the start bit is 0 (up to 15), hence no bitshifting is needed\n    uint256 internal constant LIQUIDATION_THRESHOLD_START_BIT_POSITION = 16;\n    uint256 internal constant RESERVE_DECIMALS_START_BIT_POSITION = 48;\n    uint256 internal constant RESERVE_FACTOR_START_BIT_POSITION = 64;\n    uint256 internal constant SUPPLY_CAP_START_BIT_POSITION = 116;\n    uint256 internal constant EMODE_CATEGORY_START_BIT_POSITION = 168;\n\n    /**\n     * @notice Gets the configuration flags of the reserve\n     * @param self The reserve configuration\n     * @return The state flag representing active\n     * @return The state flag representing frozen\n     * @return The state flag representing borrowing enabled\n     * @return The state flag representing stableRateBorrowing enabled\n     * @return The state flag representing paused\n     */\n    function getFlags(\n        DataTypesV3.ReserveConfigurationMap memory self\n    ) internal pure returns (bool, bool, bool, bool, bool) {\n        uint256 dataLocal = self.data;\n\n        return (\n            (dataLocal & ~ACTIVE_MASK) != 0,\n            (dataLocal & ~FROZEN_MASK) != 0,\n            (dataLocal & ~BORROWING_MASK) != 0,\n            (dataLocal & ~STABLE_BORROWING_MASK) != 0,\n            (dataLocal & ~PAUSED_MASK) != 0\n        );\n    }\n\n    /**\n     * @notice Gets the supply cap of the reserve\n     * @param self The reserve configuration\n     * @return The supply cap\n     */\n    function getSupplyCap(\n        DataTypesV3.ReserveConfigurationMap memory self\n    ) internal pure returns (uint256) {\n        return (self.data & ~SUPPLY_CAP_MASK) >> SUPPLY_CAP_START_BIT_POSITION;\n    }\n\n    /**\n     * @notice Gets the decimals of the underlying asset of the reserve\n     * @param self The reserve configuration\n     * @return The decimals of the asset\n     */\n    function getDecimals(\n        DataTypesV3.ReserveConfigurationMap memory self\n    ) internal pure returns (uint256) {\n        return\n            (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;\n    }\n\n    /**\n     * @notice Gets the reserve factor of the reserve\n     * @param self The reserve configuration\n     * @return The reserve factor\n     */\n    function getReserveFactor(\n        DataTypesV3.ReserveConfigurationMap memory self\n    ) internal pure returns (uint256) {\n        return\n            (self.data & ~RESERVE_FACTOR_MASK) >>\n            RESERVE_FACTOR_START_BIT_POSITION;\n    }\n\n    /**\n     * @notice Gets the liquidation threshold of the reserve\n     * @param self The reserve configuration\n     * @return The liquidation threshold\n    */\n    function getLiquidationThreshold(\n        DataTypesV3.ReserveConfigurationMap memory self\n    ) internal pure returns (uint256) {\n        return (self.data & ~LIQUIDATION_THRESHOLD_MASK) >> LIQUIDATION_THRESHOLD_START_BIT_POSITION;\n    }\n}\n"
      },
      "contracts/src/libraries/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\nimport { SafeERC20 as OZSafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n// solhint-disable avoid-low-level-calls\n// solhint-disable max-line-length\n\n/// @title SafeERC20 provides helper functions for safe transfers as well as safe metadata access\n/// @author Library originally written by @Boring_Crypto github.com/boring_crypto, modified by Drake Evans (Frax Finance) github.com/drakeevans\n/// @dev original: https://github.com/boringcrypto/BoringSolidity/blob/fed25c5d43cb7ce20764cd0b838e21a02ea162e9/contracts/libraries/BoringERC20.sol\nlibrary SafeERC20 {\n    bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()\n    bytes4 private constant SIG_NAME = 0x06fdde03; // name()\n    bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()\n\n    function returnDataToString(bytes memory data) internal pure returns (string memory) {\n        if (data.length >= 64) {\n            return abi.decode(data, (string));\n        } else if (data.length == 32) {\n            uint8 i = 0;\n            while (i < 32 && data[i] != 0) {\n                i++;\n            }\n            bytes memory bytesArray = new bytes(i);\n            for (i = 0; i < 32 && data[i] != 0; i++) {\n                bytesArray[i] = data[i];\n            }\n            return string(bytesArray);\n        } else {\n            return \"???\";\n        }\n    }\n\n    /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.\n    /// @param token The address of the ERC-20 token contract.\n    /// @return (string) Token symbol.\n    function safeSymbol(IERC20 token) internal view returns (string memory) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));\n        return success ? returnDataToString(data) : \"???\";\n    }\n\n    /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.\n    /// @param token The address of the ERC-20 token contract.\n    /// @return (string) Token name.\n    function safeName(IERC20 token) internal view returns (string memory) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));\n        return success ? returnDataToString(data) : \"???\";\n    }\n\n    /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.\n    /// @param token The address of the ERC-20 token contract.\n    /// @return (uint8) Token decimals.\n    function safeDecimals(IERC20 token) internal view returns (uint8) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));\n        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n    }\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        OZSafeERC20.safeTransfer(token, to, value);\n    }\n\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        OZSafeERC20.safeTransferFrom(token, from, to, value);\n    }\n}\n"
      },
      "contracts/src/libraries/VaultAccount.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nstruct VaultAccount {\n    uint128 amount; // Total amount, analogous to market cap\n    uint128 shares; // Total shares, analogous to shares outstanding\n}\n\n/// @title VaultAccount Library\n/// @author Drake Evans (Frax Finance) github.com/drakeevans, modified from work by @Boring_Crypto github.com/boring_crypto\n/// @notice Provides a library for use with the VaultAccount struct, provides convenient math implementations\n/// @dev Uses uint128 to save on storage\nlibrary VaultAccountingLibrary {\n    /// @notice Calculates the shares value in relationship to `amount` and `total`\n    /// @dev Given an amount, return the appropriate number of shares\n    function toShares(VaultAccount memory total, uint256 amount, bool roundUp) internal pure returns (uint256 shares) {\n        if (total.amount == 0) {\n            shares = amount;\n        } else {\n            shares = (amount * total.shares) / total.amount;\n            if (roundUp && (shares * total.amount) / total.shares < amount) {\n                shares = shares + 1;\n            }\n        }\n    }\n\n    /// @notice Calculates the amount value in relationship to `shares` and `total`\n    /// @dev Given a number of shares, returns the appropriate amount\n    function toAmount(VaultAccount memory total, uint256 shares, bool roundUp) internal pure returns (uint256 amount) {\n        if (total.shares == 0) {\n            amount = shares;\n        } else {\n            amount = (shares * total.amount) / total.shares;\n            if (roundUp && (amount * total.shares) / total.amount < shares) {\n                amount = amount + 1;\n            }\n        }\n    }\n}\n"
      },
      "contracts/src/LinearInterestRate.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ======================= LinearInterestRate =========================\n\nimport { IRateCalculator } from \"./interfaces/IRateCalculator.sol\";\n\n/// @title A formula for calculating interest rates linearly as a function of utilization\n/// @author Drake Evans github.com/drakeevans\ncontract LinearInterestRate is IRateCalculator {\n    uint256 private constant MIN_INT = 0; // 0.00% annual rate\n    uint256 private constant MAX_INT = 146_248_508_681; // 10,000% annual rate\n    uint256 private constant MAX_VERTEX_UTIL = 1e5; // 100%\n    uint256 private constant UTIL_PREC = 1e5;\n\n    /// @notice The ```name``` function returns the name of the rate contract\n    /// @return memory name of contract\n    function name() external pure returns (string memory) {\n        return \"Linear Interest Rate\";\n    }\n\n    /// @notice The ```getConstants``` function returns abi encoded constants\n    /// @return _calldata abi.encode(uint256 MIN_INT, uint256 MAX_INT, uint256 MAX_VERTEX_UTIL, uint256 UTIL_PREC)\n    function getConstants() external pure returns (bytes memory _calldata) {\n        return abi.encode(MIN_INT, MAX_INT, MAX_VERTEX_UTIL, UTIL_PREC);\n    }\n\n    /// @notice The ```requireValidInitData``` function reverts if initialization data fails to be validated\n    /// @param _initData abi.encode(uint256 _minInterest, uint256 _vertexInterest, uint256 _maxInterest, uint256 _vertexUtilization)\n    function requireValidInitData(bytes calldata _initData) public pure {\n        (uint256 _minInterest, uint256 _vertexInterest, uint256 _maxInterest, uint256 _vertexUtilization) = abi.decode(\n            _initData,\n            (uint256, uint256, uint256, uint256)\n        );\n        require(\n            _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT,\n            \"LinearInterestRate: _minInterest < MAX_INT && _minInterest <= _vertexInterest && _minInterest >= MIN_INT\"\n        );\n        require(\n            _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT,\n            \"LinearInterestRate: _maxInterest <= MAX_INT && _vertexInterest <= _maxInterest && _maxInterest > MIN_INT\"\n        );\n        require(\n            _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0,\n            \"LinearInterestRate: _vertexUtilization < MAX_VERTEX_UTIL && _vertexUtilization > 0\"\n        );\n    }\n\n    /// @notice Calculates interest rates using two linear functions f(utilization)\n    /// @dev We use calldata to remain un-opinionated about future implementations\n    /// @param _data abi.encode(uint64 _currentRatePerSec, uint256 _deltaTime, uint256 _utilization, uint256 _deltaBlocks)\n    /// @param _initData abi.encode(uint256 _minInterest, uint256 _vertexInterest, uint256 _maxInterest, uint256 _vertexUtilization)\n    /// @return _newRatePerSec The new interest rate per second, 1e18 precision\n    function getNewRate(bytes calldata _data, bytes calldata _initData) external pure returns (uint64 _newRatePerSec) {\n        requireValidInitData(_initData);\n        (, , uint256 _utilization, ) = abi.decode(_data, (uint64, uint256, uint256, uint256));\n        (uint256 _minInterest, uint256 _vertexInterest, uint256 _maxInterest, uint256 _vertexUtilization) = abi.decode(\n            _initData,\n            (uint256, uint256, uint256, uint256)\n        );\n        if (_utilization < _vertexUtilization) {\n            uint256 _slope = ((_vertexInterest - _minInterest) * UTIL_PREC) / _vertexUtilization;\n            _newRatePerSec = uint64(_minInterest + ((_utilization * _slope) / UTIL_PREC));\n        } else if (_utilization > _vertexUtilization) {\n            uint256 _slope = (((_maxInterest - _vertexInterest) * UTIL_PREC) / (UTIL_PREC - _vertexUtilization));\n            _newRatePerSec = uint64(_vertexInterest + (((_utilization - _vertexUtilization) * _slope) / UTIL_PREC));\n        } else {\n            _newRatePerSec = uint64(_vertexInterest);\n        }\n    }\n}\n"
      },
      "contracts/src/oracles/CrvUSDCRVOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\n/// @title CrvUSDCRVOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for CrvUSD/CRV\ninterface ILLAMMA {\n    function price_oracle() external view returns (uint256);\n}\n\ncontract CrvUSDCRVOracle {\n    address private constant ETH_CRVUSD_AMM_CONTROLLER = 0x1681195C176239ac5E72d9aeBaCf5b2492E0C4ee;\n    address private constant ETH_USD_CHAINLINK = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;\n    address private constant CRV_USD_CHAINLINK = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;\n    address private constant CRVUSD_USD_CHAINLINK = 0xEEf0C605546958c1f899b6fB336C20671f9cD49F;\n    uint8 public constant DECIMALS = 18;\n    \n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 rate = ILLAMMA(ETH_CRVUSD_AMM_CONTROLLER).price_oracle();  // ETH/crvUSD\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(ETH_USD_CHAINLINK)\n            .latestRoundData();     // ETH/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        rate = uint256(_answer) * 1e18 / rate;    // crvUSD/USD\n\n        (, _answer, , _updatedAt, ) = AggregatorV3Interface(CRVUSD_USD_CHAINLINK)\n            .latestRoundData();     // crvUSD/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        rate = Math.min(rate, uint256(_answer));\n\n        (, _answer, , _updatedAt, ) = AggregatorV3Interface(CRV_USD_CHAINLINK)\n            .latestRoundData();     // CRV/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        rate = rate * 1e18 / uint256(_answer);    // crvUSD/CRV\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/CrvUSDYv3CRVCrvUSDOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ICurvePool } from \"../interfaces/Curve/ICurvePool.sol\";\nimport { IYearnVault } from \"../interfaces/Yearn/IYearnVault.sol\";\n\n/// @title CrvUSDYv3CRVCrvUSDOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for CrvUSD/Yv3CRVCrvUSD\ninterface ILLAMMA {\n    function price_oracle() external view returns (uint256);\n}\n\ncontract CrvUSDYv3CRVCrvUSDOracle {\n    address private constant ETH_CRVUSD_AMM_CONTROLLER = 0x1681195C176239ac5E72d9aeBaCf5b2492E0C4ee;\n    address private constant ETH_USD_CHAINLINK = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;\n    address private constant CRVUSD_USD_CHAINLINK = 0xEEf0C605546958c1f899b6fB336C20671f9cD49F;\n    uint8 public constant DECIMALS = 18;\n\n    address public immutable THREECRV_ETH_CHAINLINK;\n    address public immutable CURVE_CRVUSD_3CRV_POOL;\n    address public immutable YEARN_CRVUSD_3CRV_VAULT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        address _ethUnitchainlinkAddress,\n        address _curvePoolAddress,\n        address _yearnVaultAddress,\n        string memory _name\n    ) {\n        THREECRV_ETH_CHAINLINK = _ethUnitchainlinkAddress;\n        CURVE_CRVUSD_3CRV_POOL = _curvePoolAddress;\n        YEARN_CRVUSD_3CRV_VAULT = _yearnVaultAddress;\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 crvUSDPriceInETH = _getCrvUSDPrice();\n        uint256 yvLPTokenPriceInETH = _getYv3CRVCrvUSDPrice(crvUSDPriceInETH);\n\n        uint256 rate = crvUSDPriceInETH * 1e18 / yvLPTokenPriceInETH;    // crvUSD/yv3CRVCrvUSD\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    /**\n     * @dev Get price for crvUSD\n     */\n    function _getCrvUSDPrice() internal view returns (uint256) {\n        // Get crvUSD price from AMM controller\n        uint256 crvUSDPrice;\n        uint256 rate = ILLAMMA(ETH_CRVUSD_AMM_CONTROLLER).price_oracle();  // ETH/crvUSD\n        rate = 1e36 / rate; // crvUSD/ETH\n\n        // Get crvUSD price from chainlink\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CRVUSD_USD_CHAINLINK)\n            .latestRoundData();     // crvUSD/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        crvUSDPrice = uint256(_answer);\n\n        // Get ETH price from chainlink\n        (, _answer, , _updatedAt, ) = AggregatorV3Interface(ETH_USD_CHAINLINK)\n            .latestRoundData();     // ETH/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        crvUSDPrice = crvUSDPrice * 1e18 / uint256(_answer);    // crvUSD/ETH\n\n        return Math.min(rate, crvUSDPrice);\n    }\n\n    /**\n     * @dev Get price for yearn Curve-(USDT/USDC/DAI/FRAX)-CrvUSD LP Token\n     */\n    function _getYv3CRVCrvUSDPrice(uint256 _crvUSDPrice) internal view returns (uint256) {\n        // Get (USDT/USDC/DAI/FRAX) price from chainlink\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(THREECRV_ETH_CHAINLINK)\n            .latestRoundData();     // 3CRV/ETH\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n\n        uint256 minStable = Math.min(uint256(_answer), _crvUSDPrice);\n        uint256 curveLPTokenPrice = (ICurvePool(CURVE_CRVUSD_3CRV_POOL).get_virtual_price() * minStable) / 1e18;\n\n        return curveLPTokenPrice * IYearnVault(YEARN_CRVUSD_3CRV_VAULT).pricePerShare() / 1e18;\n    }\n}\n"
      },
      "contracts/src/oracles/CrvUSDYvMkUSDCrvUSDOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ICurvePool } from \"../interfaces/Curve/ICurvePool.sol\";\nimport { IYearnVault } from \"../interfaces/Yearn/IYearnVault.sol\";\n\n/// @title CrvUSDYvMkUSDCrvUSDOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for CrvUSD/YvMkUSDCrvUSD\ninterface ILLAMMA {\n    function price_oracle() external view returns (uint256);\n}\n\ncontract CrvUSDYvMkUSDCrvUSDOracle {\n    address private constant ETH_CRVUSD_AMM_CONTROLLER = 0x1681195C176239ac5E72d9aeBaCf5b2492E0C4ee;\n    address private constant ETH_USD_CHAINLINK = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419;\n    address private constant CRVUSD_USD_CHAINLINK = 0xEEf0C605546958c1f899b6fB336C20671f9cD49F;\n    address public constant CURVE_CRVUSD_MKUSD_POOL = 0x3de254A0f838a844F727fee81040e0FA7884B935;\n    address public constant YEARN_CRVUSD_MKUSD_VAULT = 0xd901DCf4948a29d7D9D7E015AAF61591825AC267;\n    uint8 public constant DECIMALS = 18;\n    \n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 crvUSDPriceInETH = _getCrvUSDPrice();\n        uint256 yvLPTokenPriceInETH = _getYvMkUSDCrvUSDPrice(crvUSDPriceInETH);\n\n        uint256 rate = crvUSDPriceInETH * 1e18 / yvLPTokenPriceInETH;    // crvUSD/yvMkUSDCrvUSD\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    /**\n     * @dev Get price for crvUSD\n     */\n    function _getCrvUSDPrice() internal view returns (uint256) {\n        // Get crvUSD price from AMM controller\n        uint256 crvUSDPrice;\n        uint256 rate = ILLAMMA(ETH_CRVUSD_AMM_CONTROLLER).price_oracle();  // ETH/crvUSD\n        rate = 1e36 / rate; // crvUSD/ETH\n\n        // Get crvUSD price from chainlink\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CRVUSD_USD_CHAINLINK)\n            .latestRoundData();     // crvUSD/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        crvUSDPrice = uint256(_answer);\n\n        // Get ETH price from chainlink\n        (, _answer, , _updatedAt, ) = AggregatorV3Interface(ETH_USD_CHAINLINK)\n            .latestRoundData();     // ETH/USD\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert CHAINLINK_BAD_PRICE();\n        }\n        crvUSDPrice = crvUSDPrice * 1e18 / uint256(_answer);    // crvUSD/ETH\n\n        return Math.min(rate, crvUSDPrice);\n    }\n\n    /**\n     * @dev Get price for yearn Curve-MKUSD-CrvUSD LP Token\n     */\n    function _getYvMkUSDCrvUSDPrice(uint256 _crvUSDPrice) internal view returns (uint256) {\n        // Get MKUSD price from curve pool\n        uint256 mkUSDRatio = ICurvePool(CURVE_CRVUSD_MKUSD_POOL).price_oracle();\n        uint256 minStable = Math.min(mkUSDRatio, 1e18) * _crvUSDPrice / 1e18;\n        uint256 curveLPTokenPrice = (ICurvePool(CURVE_CRVUSD_MKUSD_POOL).get_virtual_price() * minStable) / 1e18;\n\n        return curveLPTokenPrice * IYearnVault(YEARN_CRVUSD_MKUSD_VAULT).pricePerShare() / 1e18;\n    }\n}\n"
      },
      "contracts/src/oracles/dual-oracles/DualOracleChainlinkUniV3.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ==================== DualOracleChainlinkUniV3 ======================\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport { IStaticOracle } from \"@mean-finance/uniswap-v3-oracle/solidity/interfaces/IStaticOracle.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Timelock2Step } from \"../../Timelock2Step.sol\";\n\n/// @title DualOracleChainlinkUniV3\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  An oracle for combining Chainlink & UniV3 Twap prices\ncontract DualOracleChainlinkUniV3 is Timelock2Step {\n    uint128 public constant ORACLE_PRECISION = 1e18;\n    address public immutable BASE_TOKEN;\n    address public immutable QUOTE_TOKEN;\n\n    // Chainlink Config\n    address public immutable CHAINLINK_MULTIPLY_ADDRESS;\n    address public immutable CHAINLINK_DIVIDE_ADDRESS;\n    uint256 public immutable CHAINLINK_NORMALIZATION;\n    uint256 public maxOracleDelay;\n\n    // Uni V3 Data\n    address public immutable UNI_V3_PAIR_ADDRESS;\n    uint32 public immutable TWAP_DURATION;\n\n    // Config Data\n    uint8 internal constant DECIMALS = 18;\n    string public name;\n    uint256 public oracleType = 1;\n\n    // events\n    /// @notice The ```SetMaxOracleDelay``` event is emitted when the max oracle delay is set\n    /// @param oldMaxOracleDelay The old max oracle delay\n    /// @param newMaxOracleDelay The new max oracle delay\n    event SetMaxOracleDelay(uint256 oldMaxOracleDelay, uint256 newMaxOracleDelay);\n\n    constructor(\n        address _baseToken,\n        address _quoteToken,\n        address _chainlinkMultiplyAddress,\n        address _chainlinkDivideAddress,\n        uint256 _maxOracleDelay,\n        address _uniV3PairAddress,\n        uint32 _twapDuration,\n        address _timelockAddress,\n        string memory _name\n    ) Timelock2Step() {\n        _setTimelock({ _newTimelock: _timelockAddress });\n\n        BASE_TOKEN = _baseToken;\n        QUOTE_TOKEN = _quoteToken;\n        CHAINLINK_MULTIPLY_ADDRESS = _chainlinkMultiplyAddress;\n        CHAINLINK_DIVIDE_ADDRESS = _chainlinkDivideAddress;\n        uint8 _multiplyDecimals = _chainlinkMultiplyAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkMultiplyAddress).decimals()\n            : 0;\n        uint8 _divideDecimals = _chainlinkDivideAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkDivideAddress).decimals()\n            : 0;\n        CHAINLINK_NORMALIZATION =\n            10 **\n                (18 +\n                    _multiplyDecimals -\n                    _divideDecimals +\n                    IERC20Metadata(_baseToken).decimals() -\n                    IERC20Metadata(_quoteToken).decimals());\n\n        maxOracleDelay = _maxOracleDelay;\n\n        UNI_V3_PAIR_ADDRESS = _uniV3PairAddress;\n        if (_twapDuration == 0) revert(\"DURATION == 0\");\n        TWAP_DURATION = _twapDuration;\n\n        name = _name;\n    }\n\n    /// @notice The ```setMaxOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale\n    /// @dev Requires msg.sender to be the timelock address\n    /// @param _newMaxOracleDelay The new max oracle delay\n    function setMaxOracleDelay(uint256 _newMaxOracleDelay) external {\n        _requireTimelock();\n        emit SetMaxOracleDelay(maxOracleDelay, _newMaxOracleDelay);\n        maxOracleDelay = _newMaxOracleDelay;\n    }\n\n    function _getChainlinkPrice() internal view returns (bool _isBadData, uint256 _price) {\n        _price = uint256(1e36);\n\n        if (CHAINLINK_MULTIPLY_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_MULTIPLY_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > maxOracleDelay)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price * uint256(_answer);\n        }\n\n        if (CHAINLINK_DIVIDE_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_DIVIDE_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > maxOracleDelay)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price / uint256(_answer);\n        }\n\n        // return price as ratio of Collateral/Asset including decimal differences\n        // CHAINLINK_NORMALIZATION = 10**(18 + asset.decimals() - collateral.decimals() + multiplyOracle.decimals() - divideOracle.decimals())\n        _price = _price / CHAINLINK_NORMALIZATION;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return two prices from different oracles\n    /// @return _isBadData is true when chainlink data is stale or negative\n    /// @return _priceLow is the lower of the two prices\n    /// @return _priceHigh is the higher of the two prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 _price1;\n        if (UNI_V3_PAIR_ADDRESS != address(0)) {\n            address[] memory _pools = new address[](1);\n            _pools[0] = UNI_V3_PAIR_ADDRESS;\n            _price1 = IStaticOracle(0xB210CE856631EeEB767eFa666EC7C1C57738d438).quoteSpecificPoolsWithTimePeriod(\n                ORACLE_PRECISION,\n                BASE_TOKEN,\n                QUOTE_TOKEN,\n                _pools,\n                TWAP_DURATION\n            );\n        }\n        uint256 _price2;\n        (_isBadData, _price2) = _getChainlinkPrice();\n\n        // If bad data return price1 for both, else set high to higher price and low to lower price\n        if (UNI_V3_PAIR_ADDRESS != address(0)) {\n            _priceLow = _isBadData || _price1 < _price2 ? _price1 : _price2;\n            _priceHigh = _isBadData || _price1 > _price2 ? _price1 : _price2;\n        } else {\n            _priceLow = _price2;\n            _priceHigh = _price2;\n        }\n    }\n\n    function decimals() external pure returns (uint8) {\n        return DECIMALS;\n    }\n}\n"
      },
      "contracts/src/oracles/ERC4626Oracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { IERC4626 } from \"../interfaces/IERC4626.sol\";\n\n/// @title ERC4626Oracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ERC4626 Token\ncontract ERC4626Oracle {\n    uint8 public constant DECIMALS = 18;\n\n    address public immutable TOKEN;\n    uint8 public immutable TOKEN_DECIMALS;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    constructor(\n        uint256 _priceMin,\n        address _token,\n        uint8 _decimals,\n        string memory _name\n    ) {\n        PRICE_MIN = _priceMin;\n        TOKEN = _token;\n        TOKEN_DECIMALS = _decimals;\n        name = _name;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 rate = IERC4626(TOKEN).convertToShares(10 ** TOKEN_DECIMALS);\n        rate = rate * 10 ** DECIMALS / 10 ** TOKEN_DECIMALS;\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHEETHPendlePTOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport \"@pendle/core-v2/contracts/oracles/PendlePtOracleLib.sol\";\nimport \"@pendle/core-v2/contracts/interfaces/IPMarket.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title ETHEETHPendlePTOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/eETH Pendle PT\ninterface IWeETH {\n    function getWeETHByeETH(uint256 _eETHAmount) external view returns (uint256);\n}\n\ncontract ETHEETHPendlePTOracle {\n    using PendlePtOracleLib for IPMarket;\n\n    address private constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;\n    address private constant REDSTONE_WEETH_ETH_PRICE = 0x8751F736E94F6CD167e8C5B97E245680FbD9CC36;\n    uint8 public constant DECIMALS = 18;\n    \n    address public immutable PENDLE_PT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint32 public immutable TWAP_DURATION;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        address _pendlePT, \n        uint32 _twapDuration, \n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        PENDLE_PT = _pendlePT;\n        TWAP_DURATION = _twapDuration;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 weETHRate = IWeETH(WEETH).getWeETHByeETH(1e18);     //  eETH/weETH\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(REDSTONE_WEETH_ETH_PRICE).latestRoundData();\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert REDSTONE_BAD_PRICE();\n        }\n        uint256 rate = weETHRate * uint256(_answer) / 1e8;       // eETH/ETH, redstone price decimal is 8\n        uint256 ptRate = IPMarket(PENDLE_PT).getPtToAssetRate(TWAP_DURATION);\n        rate = (rate * ptRate) / 1e18;       //  PT/ETH\n        rate = 1e36 / rate;     // ETH/PT\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHEETHYvPendleLPTOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport \"@pendle/core-v2/contracts/oracles/PendleLpOracleLib.sol\";\nimport \"@pendle/core-v2/contracts/interfaces/IPMarket.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC4626 } from \"../interfaces/IERC4626.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title ETHEETHYvPendleLPTOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/Yearn Vault eETH Pendle LPT\ninterface IWeETH {\n    function getWeETHByeETH(uint256 _eETHAmount) external view returns (uint256);\n}\n\ncontract ETHEETHYvPendleLPTOracle {\n    using PendleLpOracleLib for IPMarket;\n\n    address private constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;\n    address private constant REDSTONE_WEETH_ETH_PRICE = 0x8751F736E94F6CD167e8C5B97E245680FbD9CC36;\n    uint8 public constant DECIMALS = 18;\n    \n    address public immutable PENDLE_LPT;\n    address public immutable YEARN_VAULT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint32 public immutable TWAP_DURATION;\n    uint8 public immutable ASSET_DECIMALS;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        address _yearnVaultOfpendleLPT, \n        uint32 _twapDuration, \n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        YEARN_VAULT = _yearnVaultOfpendleLPT;\n        PENDLE_LPT = IERC4626(YEARN_VAULT).asset();\n        ASSET_DECIMALS = IERC20Metadata(PENDLE_LPT).decimals();\n        TWAP_DURATION = _twapDuration;\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 weETHRate = IWeETH(WEETH).getWeETHByeETH(1e18);     //  eETH/weETH\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(REDSTONE_WEETH_ETH_PRICE).latestRoundData();\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert REDSTONE_BAD_PRICE();\n        }\n        uint256 rate = weETHRate * uint256(_answer) / 1e8;       // eETH/ETH, redstone price decimal is 8\n        uint256 lpRate = IPMarket(PENDLE_LPT).getLpToAssetRate(TWAP_DURATION);\n        rate = (rate * lpRate) / 1e18;       //  LPT/ETH\n        rate = IERC4626(YEARN_VAULT).convertToShares(10 ** ASSET_DECIMALS) * rate / 1e18;       //YV_LP/ETH\n        rate = 1e36 / rate;     // ETH/YV_LP\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHRSETHPendlePTOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport \"@pendle/core-v2/contracts/oracles/PendlePtOracleLib.sol\";\nimport \"@pendle/core-v2/contracts/interfaces/IPMarket.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title ETHRSETHPendlePTOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/rsETH Pendle PT\n\ncontract ETHRSETHPendlePTOracle {\n    using PendlePtOracleLib for IPMarket;\n\n    address private constant REDSTONE_RSETH_ETH_PRICE = 0xA736eAe8805dDeFFba40cAB8c99bCB309dEaBd9B;\n    uint8 public constant DECIMALS = 18;\n    \n    address public immutable PENDLE_PT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint32 public immutable TWAP_DURATION;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        address _pendlePT, \n        uint32 _twapDuration, \n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        PENDLE_PT = _pendlePT;\n        TWAP_DURATION = _twapDuration;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(REDSTONE_RSETH_ETH_PRICE).latestRoundData();\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert REDSTONE_BAD_PRICE();\n        }\n        uint256 rate = 1e18 * uint256(_answer) / 1e8;       // rsETH/ETH, redstone price decimal is 8\n        uint256 ptRate = IPMarket(PENDLE_PT).getPtToAssetRate(TWAP_DURATION);\n        rate = (rate * ptRate) / 1e18;       //  PT/ETH\n        rate = 1e36 / rate;     // ETH/PT\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHRSWETHPendlePTOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport \"@pendle/core-v2/contracts/oracles/PendlePtOracleLib.sol\";\nimport \"@pendle/core-v2/contracts/interfaces/IPMarket.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title ETHRSWETHPendlePTOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/rswETH Pendle PT\ninterface IrswETH {\n    function rswETHToETHRate() external view returns (uint256);\n}\n\ncontract ETHRSWETHPendlePTOracle {\n    using PendlePtOracleLib for IPMarket;\n\n    address private constant TOKEN = 0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0;\n    uint8 public constant DECIMALS = 18;\n    \n    address public immutable PENDLE_PT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint32 public immutable TWAP_DURATION;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        address _pendlePT,\n        uint32 _twapDuration, \n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        PENDLE_PT = _pendlePT;\n        TWAP_DURATION = _twapDuration;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 rate = IrswETH(TOKEN).rswETHToETHRate();       // rswETH/ETH\n        uint256 ptRate = IPMarket(PENDLE_PT).getPtToAssetRate(TWAP_DURATION);\n        rate = (rate * ptRate) / 1e18;       //  PT/ETH\n\n        rate = 1e36 / rate;     //  ETH/PT\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHSWETHOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\n/// @title ETHSWETHOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/swETH\ninterface IswETH {\n    function swETHToETHRate() external view returns (uint256);\n}\n\ncontract ETHSWETHOracle {\n    address private constant TOKEN = 0xf951E335afb289353dc249e82926178EaC7DEd78;\n    address private constant REDSTONE_SWETH_ETH_PRICE = 0x061bB36F8b67bB922937C102092498dcF4619F86;\n    uint8 public constant DECIMALS = 18;\n    \n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 rate = IswETH(TOKEN).swETHToETHRate();\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(REDSTONE_SWETH_ETH_PRICE).latestRoundData();\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert REDSTONE_BAD_PRICE();\n        }\n        rate = Math.min(uint256(_answer) * 1e10, rate);       // redstone price decimal is 8\n        rate = 1e36 / rate;     //  ETH/SWETH\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/ETHSWETHYvPendleLPTOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport \"@pendle/core-v2/contracts/oracles/PendleLpOracleLib.sol\";\nimport \"@pendle/core-v2/contracts/interfaces/IPMarket.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { IERC4626 } from \"../interfaces/IERC4626.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title ETHSWETHYvPendleLPTOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for ETH/Yearn Vault swETH Pendle LPT\ninterface IswETH {\n    function swETHToETHRate() external view returns (uint256);\n}\n\ncontract ETHSWETHYvPendleLPTOracle {\n    using PendleLpOracleLib for IPMarket;\n\n    address private constant SWETH = 0xf951E335afb289353dc249e82926178EaC7DEd78;\n    address private constant REDSTONE_SWETH_ETH_PRICE = 0x061bB36F8b67bB922937C102092498dcF4619F86;\n    uint8 public constant DECIMALS = 18;\n    \n    address public immutable PENDLE_LPT;\n    address public immutable YEARN_VAULT;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint32 public immutable TWAP_DURATION;\n    uint8 public immutable ASSET_DECIMALS;\n\n    string public name;\n\n    error REDSTONE_BAD_PRICE();\n\n    constructor(\n        address _yearnVaultOfpendleLPT, \n        uint32 _twapDuration, \n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        YEARN_VAULT = _yearnVaultOfpendleLPT;\n        PENDLE_LPT = IERC4626(YEARN_VAULT).asset();\n        ASSET_DECIMALS = IERC20Metadata(PENDLE_LPT).decimals();\n        TWAP_DURATION = _twapDuration;\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 swETHRate = IswETH(SWETH).swETHToETHRate();\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(REDSTONE_SWETH_ETH_PRICE).latestRoundData();\n        // If data is stale or negative, set bad data to true and return\n        if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n            revert REDSTONE_BAD_PRICE();\n        }\n        swETHRate = Math.min(uint256(_answer) * 1e10, swETHRate);       // redstone price decimal is 8\n        \n        uint256 lpRate = IPMarket(PENDLE_LPT).getLpToAssetRate(TWAP_DURATION);\n        uint256 rate = (swETHRate * lpRate) / 1e18;       //  LPT/ETH\n        rate = IERC4626(YEARN_VAULT).convertToShares(10 ** ASSET_DECIMALS) * rate / 1e18;       //YV_LP/ETH\n        rate = 1e36 / rate;     // ETH/YV_LP\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/FruxFAssetOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title FruxFAssetOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for CrvUSD/CRV\n\ninterface IFAsset {\n    function exchangeRateStored() external view returns (uint256);\n}\n\ncontract FruxFAssetOracle {    \n    uint8 public constant DECIMALS = 18;\n\n    address public immutable FASSET;\n    address public immutable UNDERLYING_FASSET;\n    address public immutable ASSET;\n    address public immutable CHAINLINK_MULTIPLY_ADDRESS;\n    address public immutable CHAINLINK_DIVIDE_ADDRESS;\n    uint256 public immutable CHAINLINK_NORMALIZATION;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    \n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n    constructor(\n        address _fAsset,\n        address _underlyingFAsset,\n        address _asset,\n        address _chainlinkMultiplyAddress,\n        address _chainlinkDivideAddress,\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        FASSET = _fAsset;\n        UNDERLYING_FASSET = _underlyingFAsset;\n        ASSET = _asset;\n        CHAINLINK_MULTIPLY_ADDRESS = _chainlinkMultiplyAddress;\n        CHAINLINK_DIVIDE_ADDRESS = _chainlinkDivideAddress;\n\n        uint8 _multiplyDecimals = _chainlinkMultiplyAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkMultiplyAddress).decimals()\n            : 0;\n        uint8 _divideDecimals = _chainlinkDivideAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkDivideAddress).decimals()\n            : 0;\n\n        CHAINLINK_NORMALIZATION =\n            10 **\n                (18 +\n                    _multiplyDecimals -\n                    _divideDecimals +\n                    IERC20Metadata(_asset).decimals() -\n                    IERC20Metadata(_underlyingFAsset).decimals());\n\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 price;\n        (_isBadData, price) = _getChainlinkPrice();     // assetAmount * price = underlyingFAssetAmount\n        if (_isBadData) revert CHAINLINK_BAD_PRICE();\n\n        uint256 rate = IFAsset(FASSET).exchangeRateStored();    // underlyingFAssetAmount / rate = FAssetAmount, rate decimal is constant 18\n        rate = price * 1e18 / rate;\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    function _getChainlinkPrice() internal view returns (bool _isBadData, uint256 _price) {\n        _price = uint256(1e36);\n\n        if (CHAINLINK_MULTIPLY_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_MULTIPLY_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price * uint256(_answer);\n        }\n\n        if (CHAINLINK_DIVIDE_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_DIVIDE_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price / uint256(_answer);\n        }\n\n        // return price as ratio of underlyingFAsset/Asset including decimal differences\n        // CHAINLINK_NORMALIZATION = 10**(18 + asset.decimals() - underlyingFAsset.decimals() + multiplyOracle.decimals() - divideOracle.decimals())\n        _price = _price / CHAINLINK_NORMALIZATION;\n    }\n}\n"
      },
      "contracts/src/oracles/Mode/PythBasedAssetOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\n/// @title PythBasedAssetOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for assets based on pyth\n\ninterface IPyth {\n    struct Price {\n        // Price\n        int64 price;\n        // Confidence interval around the price\n        uint64 conf;\n        // Price exponent\n        int32 expo;\n        // Unix timestamp describing when the price was published\n        uint publishTime;\n    }\n\n    function getPriceUnsafe(bytes32 id) external view returns (Price memory price);\n}\n\ncontract PythBasedAssetOracle {\n    address private constant PYTH_ORACLE = 0xA2aa501b19aff244D90cc15a4Cf739D2725B5729;\n    uint8 public constant DECIMALS = 18;\n    \n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    uint256 public immutable NORMALIZATION;\n    bytes32 public immutable BORROW_ASSET_PRICE_ID;\n    bytes32 public immutable COLLATERAL_ASSET_PRICE_ID;\n\n    string public name;\n\n    error BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        address _borrowAsset,\n        address _collateralAsset,\n        bytes32 _borrowAssetPriceId,\n        bytes32 _collateralAssetPriceId,\n        string memory _name\n    ) {\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n        BORROW_ASSET_PRICE_ID = _borrowAssetPriceId;\n        COLLATERAL_ASSET_PRICE_ID = _collateralAssetPriceId;\n        \n        uint8 _multiplyDecimals = uint8(uint32(-IPyth(PYTH_ORACLE).getPriceUnsafe(BORROW_ASSET_PRICE_ID).expo));\n        uint8 _divideDecimals = uint8(uint32(-IPyth(PYTH_ORACLE).getPriceUnsafe(COLLATERAL_ASSET_PRICE_ID).expo));\n        NORMALIZATION =\n            10 **\n                (18 +\n                    _multiplyDecimals -\n                    _divideDecimals +\n                    IERC20Metadata(_borrowAsset).decimals() -\n                    IERC20Metadata(_collateralAsset).decimals());\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        IPyth.Price memory price1 = IPyth(PYTH_ORACLE).getPriceUnsafe(BORROW_ASSET_PRICE_ID);     // borrowAsset/USD\n        // If data is stale or negative, set bad data to true and return\n        if (price1.price <= 0 || (block.timestamp - price1.publishTime > MAX_ORACLE_DELAY)) {\n            revert BAD_PRICE();\n        }\n\n        IPyth.Price memory price2 = IPyth(PYTH_ORACLE).getPriceUnsafe(COLLATERAL_ASSET_PRICE_ID);   // collateralAsset/USD\n        // If data is stale or negative, set bad data to true and return\n        if (price2.price <= 0 || (block.timestamp - price2.publishTime > MAX_ORACLE_DELAY)) {\n            revert BAD_PRICE();\n        }\n\n        uint256 rate = uint256(1e36) * uint256(uint64(price1.price)) / uint256(uint64(price2.price)) / NORMALIZATION;    //borrowAsset/collateralAsset\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n}\n"
      },
      "contracts/src/oracles/Mode/RedstoneBasedAssetOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n/// @title RedstoneBasedAssetOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for assets based on redstone\n\ninterface IPriceCalculator {\n  function priceOf(address asset) external view returns (uint256);\n\n  function priceOfETH() external view returns (uint256);\n\n  function getTimestampsFromLatestUpdate() external view returns (uint128 dataTimestamp, uint128 blockTimestamp);\n}\n\ncontract RedstoneBasedAssetOracle {\n    address private constant REDSTONE_ORACLE = 0x7C1DAAE7BB0688C9bfE3A918A4224041c7177256;\n    address private constant WETH = 0x4200000000000000000000000000000000000006;\n\n    uint8 public constant DECIMALS = 18;\n    \n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n    address public immutable BORROW_ASSET;\n    address public immutable COLLATERAL_ASSET;\n\n    string public name;\n\n    error BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        address _borrowAsset,\n        address _collateralAsset,\n        string memory _name\n    ) {\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n        BORROW_ASSET = _borrowAsset;\n        COLLATERAL_ASSET = _collateralAsset;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 borrowAssetPrice = _getPriceOfAsset(BORROW_ASSET);              // borrowAsset/USD   decimal 18\n        uint256 collateralAssetPrice = _getPriceOfAsset(COLLATERAL_ASSET);      // collateralAsset/USD\n        uint256 rate = borrowAssetPrice * 1e18 / collateralAssetPrice;          // borrowAsset/collateralAsset\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    function _getPriceOfAsset(address _asset) internal view returns (uint256) {\n        (, uint128 blockTimestamp) = IPriceCalculator(REDSTONE_ORACLE).getTimestampsFromLatestUpdate();\n        // If data is stale, revert\n        if (block.timestamp - blockTimestamp > MAX_ORACLE_DELAY) {\n            revert BAD_PRICE();\n        }\n\n        if (_asset == WETH) {\n            return IPriceCalculator(REDSTONE_ORACLE).priceOfETH();\n        }\n\n        return IPriceCalculator(REDSTONE_ORACLE).priceOf(_asset);\n    }\n}\n"
      },
      "contracts/src/oracles/PxETHBalPxETHOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ICurvePool } from \"../interfaces/Curve/ICurvePool.sol\";\n\n/// @title PxETHBalPxETHOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for PxETH/BalPxETH\n\ncontract PxETHBalPxETHOracle {\n    uint8 public constant DECIMALS = 18;\n\n    address public immutable BAL_PXETH_POOL;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        address _balPoolAddress,\n        string memory _name\n    ) {\n        BAL_PXETH_POOL = _balPoolAddress;\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        // uint256 yvLPTokenPriceInETH = _getYv3CRVCrvUSDPrice(crvUSDPriceInETH);\n\n        // uint256 rate = crvUSDPriceInETH * 1e18 / yvLPTokenPriceInETH;    // crvUSD/yv3CRVCrvUSD\n        uint256 rate = 1e18;\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    // /**\n    //  * @dev Get price for yearn Curve-(USDT/USDC/DAI/FRAX)-CrvUSD LP Token\n    //  */\n    // function _getYv3CRVCrvUSDPrice(uint256 _crvUSDPrice) internal view returns (uint256) {\n    //     // Get (USDT/USDC/DAI/FRAX) price from chainlink\n    //     (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(THREECRV_ETH_CHAINLINK)\n    //         .latestRoundData();     // 3CRV/ETH\n    //     // If data is stale or negative, set bad data to true and return\n    //     if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n    //         revert CHAINLINK_BAD_PRICE();\n    //     }\n\n    //     uint256 minStable = Math.min(uint256(_answer), _crvUSDPrice);\n    //     uint256 curveLPTokenPrice = (ICurvePool(BAL_PXETH_POOL).get_virtual_price() * minStable) / 1e18;\n\n    //     return curveLPTokenPrice * IYearnVault(YEARN_CRVUSD_3CRV_VAULT).pricePerShare() / 1e18;\n    // }\n}\n"
      },
      "contracts/src/oracles/PxETHUniV3BunniPxETHOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ICurvePool } from \"../interfaces/Curve/ICurvePool.sol\";\n\n/// @title PxETHUniV3BunniPxETHOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for PxETH/UniV3BunniPxETH\n\ncontract PxETHUniV3BunniPxETHOracle {\n    uint8 public constant DECIMALS = 18;\n\n    address public immutable UNIV3_BUNNI_PXETH_POOL;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        address _univ3BunniPoolAddress,\n        string memory _name\n    ) {\n        UNIV3_BUNNI_PXETH_POOL = _univ3BunniPoolAddress;\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        // uint256 yvLPTokenPriceInETH = _getYv3CRVCrvUSDPrice(crvUSDPriceInETH);\n\n        // uint256 rate = crvUSDPriceInETH * 1e18 / yvLPTokenPriceInETH;    // crvUSD/yv3CRVCrvUSD\n        uint256 rate = 1e18;\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    // /**\n    //  * @dev Get price for yearn Curve-(USDT/USDC/DAI/FRAX)-CrvUSD LP Token\n    //  */\n    // function _getYv3CRVCrvUSDPrice(uint256 _crvUSDPrice) internal view returns (uint256) {\n    //     // Get (USDT/USDC/DAI/FRAX) price from chainlink\n    //     (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(THREECRV_ETH_CHAINLINK)\n    //         .latestRoundData();     // 3CRV/ETH\n    //     // If data is stale or negative, set bad data to true and return\n    //     if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n    //         revert CHAINLINK_BAD_PRICE();\n    //     }\n\n    //     uint256 minStable = Math.min(uint256(_answer), _crvUSDPrice);\n    //     uint256 curveLPTokenPrice = (ICurvePool(UNIV3_BUNNI_PXETH_POOL).get_virtual_price() * minStable) / 1e18;\n\n    //     return curveLPTokenPrice * IYearnVault(YEARN_CRVUSD_3CRV_VAULT).pricePerShare() / 1e18;\n    // }\n}\n"
      },
      "contracts/src/oracles/PxETHYvStETHPxETHOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport { ICurvePool } from \"../interfaces/Curve/ICurvePool.sol\";\nimport { IYearnVault } from \"../interfaces/Yearn/IYearnVault.sol\";\n\n/// @title PxETHYvStETHPxETHOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for PxETH/YvStETHPxETH\n\ncontract PxETHYvStETHPxETHOracle {\n    address public constant STETH_CHAINLINK = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;\n    address public constant CURVE_PXETH_STETH_POOL = 0x6951bDC4734b9f7F3E1B74afeBC670c736A0EDB6;\n    address public constant YEARN_PXETH_STETH_VAULT = 0x2c8a33C66c00264316Ea4E4433e86A386Eb6ECBf;\n    uint8 public constant DECIMALS = 18;\n\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 rate = _getYvStETHPxETHPrice();    // Assume 1PxETH = 1ETH\n        rate = 1e36 / rate;     // PxETH/YvStETHPxETH\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    /**\n     * @dev Get price for Yearn Curve-stETH-pxETH LP Token, 1 pxETH <= 1ETH\n     */\n    function _getYvStETHPxETHPrice() internal view returns (uint256) {\n        // Get stETH price from chainlink\n        (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(STETH_CHAINLINK)\n            .latestRoundData();     // stETH/ETH\n        // If data is stale or negative, set bad data to true and return\n        // if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n        //     revert CHAINLINK_BAD_PRICE();\n        // }\n\n        uint256 minPrice = Math.min(uint256(_answer), 1e18);\n        uint256 curveLPTokenPrice = (ICurvePool(CURVE_PXETH_STETH_POOL).get_virtual_price() * minPrice) / 1e18;\n\n        return curveLPTokenPrice;\n    }\n}\n"
      },
      "contracts/src/oracles/SFRAXOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\nimport { AggregatorV3Interface } from \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC4626 } from \"../interfaces/IERC4626.sol\";\n\n/// @title SFRAXOracle\n/// @author Jason (Sturdy) https://github.com/iris112\n/// @notice  An oracle for CrvUSD/CRV\n\ninterface IFAsset {\n    function exchangeRateStored() external view returns (uint256);\n}\n\ncontract SFRAXOracle {\n    address public constant SFRAX = 0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32;\n    address public constant FRAX = 0x853d955aCEf822Db058eb8505911ED77F175b99e;\n    uint8 public constant DECIMALS = 18;\n\n    address public immutable ASSET;\n    address public immutable CHAINLINK_MULTIPLY_ADDRESS;\n    address public immutable CHAINLINK_DIVIDE_ADDRESS;\n    uint256 public immutable CHAINLINK_NORMALIZATION;\n    uint256 public immutable MAX_ORACLE_DELAY;\n    uint256 public immutable PRICE_MIN;\n\n    string public name;\n\n    error CHAINLINK_BAD_PRICE();\n\n    constructor(\n        address _asset,\n        address _chainlinkMultiplyAddress,\n        address _chainlinkDivideAddress,\n        uint256 _maxOracleDelay,\n        uint256 _priceMin,\n        string memory _name\n    ) {\n        ASSET = _asset;\n        CHAINLINK_MULTIPLY_ADDRESS = _chainlinkMultiplyAddress;\n        CHAINLINK_DIVIDE_ADDRESS = _chainlinkDivideAddress;\n\n        uint8 _multiplyDecimals = _chainlinkMultiplyAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkMultiplyAddress).decimals()\n            : 0;\n        uint8 _divideDecimals = _chainlinkDivideAddress != address(0)\n            ? AggregatorV3Interface(_chainlinkDivideAddress).decimals()\n            : 0;\n\n        CHAINLINK_NORMALIZATION =\n            10 **\n                (18 +\n                    _multiplyDecimals -\n                    _divideDecimals +\n                    IERC20Metadata(_asset).decimals() -\n                    IERC20Metadata(FRAX).decimals());\n\n        name = _name;\n        MAX_ORACLE_DELAY = _maxOracleDelay;\n        PRICE_MIN = _priceMin;\n    }\n\n    /// @notice The ```getPrices``` function is intended to return price of ERC4626 token based on the base asset\n    /// @return _isBadData is always false, just sync to other oracle interfaces\n    /// @return _priceLow is the lower of the prices\n    /// @return _priceHigh is the higher of the prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 price;\n        (_isBadData, price) = _getChainlinkPrice();     // assetAmount * price = FRAXAmount\n        if (_isBadData) revert CHAINLINK_BAD_PRICE();\n\n        uint256 rate = IERC4626(SFRAX).convertToShares(10 ** 18);    // FraxAmount * rate = SFRAXAmount, rate decimal is 18\n        rate = price * rate / 1e18;\n\n        _priceHigh = rate > PRICE_MIN ? rate : PRICE_MIN;\n        _priceLow = _priceHigh;\n    }\n\n    function _getChainlinkPrice() internal view returns (bool _isBadData, uint256 _price) {\n        _price = uint256(1e36);\n\n        if (CHAINLINK_MULTIPLY_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_MULTIPLY_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price * uint256(_answer);\n        }\n\n        if (CHAINLINK_DIVIDE_ADDRESS != address(0)) {\n            (, int256 _answer, , uint256 _updatedAt, ) = AggregatorV3Interface(CHAINLINK_DIVIDE_ADDRESS)\n                .latestRoundData();\n\n            // If data is stale or negative, set bad data to true and return\n            if (_answer <= 0 || (block.timestamp - _updatedAt > MAX_ORACLE_DELAY)) {\n                _isBadData = true;\n                return (_isBadData, _price);\n            }\n            _price = _price / uint256(_answer);\n        }\n\n        // return price as ratio of underlyingFAsset/Asset including decimal differences\n        // CHAINLINK_NORMALIZATION = 10**(18 + asset.decimals() - underlyingFAsset.decimals() + multiplyOracle.decimals() - divideOracle.decimals())\n        _price = _price / CHAINLINK_NORMALIZATION;\n    }\n}\n"
      },
      "contracts/src/SturdyPair.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ========================== SturdyPair ============================\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SturdyPairCore } from \"./SturdyPairCore.sol\";\nimport { SafeERC20 } from \"./libraries/SafeERC20.sol\";\nimport { VaultAccount, VaultAccountingLibrary } from \"./libraries/VaultAccount.sol\";\nimport { IRateCalculatorV2 } from \"./interfaces/IRateCalculatorV2.sol\";\n\n/// @title SturdyPair\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  The SturdyPair is a lending pair that allows users to engage in lending and borrowing activities\ncontract SturdyPair is IERC20Metadata, SturdyPairCore {\n    using VaultAccountingLibrary for VaultAccount;\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n\n    /// @param _configData abi.encode(address _asset, address _collateral, address _oracle, uint32 _maxOracleDeviation, address _rateContract, uint64 _fullUtilizationRate, uint256 _maxLTV, uint256 _cleanLiquidationFee, uint256 _dirtyLiquidationFee, uint256 _protocolLiquidationFee)\n    /// @param _immutables abi.encode(address _circuitBreakerAddress, address _comptrollerAddress, address _timelockAddress)\n    /// @param _customConfigData abi.encode(string memory _nameOfContract, string memory _symbolOfContract, uint8 _decimalsOfContract)\n    constructor(\n        bytes memory _configData,\n        bytes memory _immutables,\n        bytes memory _customConfigData\n    ) SturdyPairCore(_configData, _immutables, _customConfigData) {}\n\n    // ============================================================================================\n    // ERC20 Metadata\n    // ============================================================================================\n\n    function name() public view override(ERC20, IERC20Metadata) returns (string memory) {\n        return nameOfContract;\n    }\n\n    function symbol() public view override(ERC20, IERC20Metadata) returns (string memory) {\n        return symbolOfContract;\n    }\n\n    function decimals() public view override(ERC20, IERC20Metadata) returns (uint8) {\n        return decimalsOfContract;\n    }\n\n    // totalSupply for fToken ERC20 compatibility\n    function totalSupply() public view override(ERC20, IERC20) returns (uint256) {\n        return totalAsset.shares;\n    }\n\n    // ============================================================================================\n    // Functions: Helpers\n    // ============================================================================================\n\n    function asset() external view returns (address) {\n        return address(assetContract);\n    }\n\n    function getConstants()\n        external\n        pure\n        returns (\n            uint256 _LTV_PRECISION,\n            uint256 _LIQ_PRECISION,\n            uint256 _UTIL_PREC,\n            uint256 _FEE_PRECISION,\n            uint256 _EXCHANGE_PRECISION,\n            uint256 _DEVIATION_PRECISION,\n            uint256 _RATE_PRECISION,\n            uint256 _MAX_PROTOCOL_FEE\n        )\n    {\n        _LTV_PRECISION = LTV_PRECISION;\n        _LIQ_PRECISION = LIQ_PRECISION;\n        _UTIL_PREC = UTIL_PREC;\n        _FEE_PRECISION = FEE_PRECISION;\n        _EXCHANGE_PRECISION = EXCHANGE_PRECISION;\n        _DEVIATION_PRECISION = DEVIATION_PRECISION;\n        _RATE_PRECISION = RATE_PRECISION;\n        _MAX_PROTOCOL_FEE = MAX_PROTOCOL_FEE;\n    }\n\n    /// @notice The ```getUserSnapshot``` function gets user level accounting data\n    /// @param _address The user address\n    /// @return _userAssetShares The user fToken balance\n    /// @return _userBorrowShares The user borrow shares\n    /// @return _userCollateralBalance The user collateral balance\n    function getUserSnapshot(\n        address _address\n    ) external view returns (uint256 _userAssetShares, uint256 _userBorrowShares, uint256 _userCollateralBalance) {\n        _userAssetShares = balanceOf(_address);\n        _userBorrowShares = userBorrowShares[_address];\n        _userCollateralBalance = userCollateralBalance[_address];\n    }\n\n    /// @notice The ```getPairAccounting``` function gets all pair level accounting numbers\n    /// @return _totalAssetAmount Total assets deposited and interest accrued, total claims\n    /// @return _totalAssetShares Total fTokens\n    /// @return _totalBorrowAmount Total borrows\n    /// @return _totalBorrowShares Total borrow shares\n    /// @return _totalCollateral Total collateral\n    function getPairAccounting()\n        external\n        view\n        returns (\n            uint128 _totalAssetAmount,\n            uint128 _totalAssetShares,\n            uint128 _totalBorrowAmount,\n            uint128 _totalBorrowShares,\n            uint256 _totalCollateral\n        )\n    {\n        (, , , , VaultAccount memory _totalAsset, VaultAccount memory _totalBorrow) = previewAddInterest();\n        _totalAssetAmount = _totalAsset.amount;\n        _totalAssetShares = _totalAsset.shares;\n        _totalBorrowAmount = _totalBorrow.amount;\n        _totalBorrowShares = _totalBorrow.shares;\n        _totalCollateral = totalCollateral;\n    }\n\n    /// @notice The ```toBorrowShares``` function converts a given amount of borrow debt into the number of shares\n    /// @param _amount Amount of borrow\n    /// @param _roundUp Whether to roundup during division\n    /// @param _previewInterest Whether to simulate interest accrual\n    /// @return _shares The number of shares\n    function toBorrowShares(\n        uint256 _amount,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _shares) {\n        if (_previewInterest) {\n            (, , , , , VaultAccount memory _totalBorrow) = previewAddInterest();\n            _shares = _totalBorrow.toShares(_amount, _roundUp);\n        } else {\n            _shares = totalBorrow.toShares(_amount, _roundUp);\n        }\n    }\n\n    /// @notice The ```toBorrowAmount``` function converts a given amount of borrow debt into the number of shares\n    /// @param _shares Shares of borrow\n    /// @param _roundUp Whether to roundup during division\n    /// @param _previewInterest Whether to simulate interest accrual\n    /// @return _amount The amount of asset\n    function toBorrowAmount(\n        uint256 _shares,\n        bool _roundUp,\n        bool _previewInterest\n    ) external view returns (uint256 _amount) {\n        if (_previewInterest) {\n            (, , , , , VaultAccount memory _totalBorrow) = previewAddInterest();\n            _amount = _totalBorrow.toAmount(_shares, _roundUp);\n        } else {\n            _amount = totalBorrow.toAmount(_shares, _roundUp);\n        }\n    }\n\n    /// @notice The ```toAssetAmount``` function converts a given number of shares to an asset amount\n    /// @param _shares Shares of asset (fToken)\n    /// @param _roundUp Whether to round up after division\n    /// @param _previewInterest Whether to preview interest accrual before calculation\n    /// @return _amount The amount of asset\n    function toAssetAmount(\n        uint256 _shares,\n        bool _roundUp,\n        bool _previewInterest\n    ) public view returns (uint256 _amount) {\n        if (_previewInterest) {\n            (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n            _amount = _totalAsset.toAmount(_shares, _roundUp);\n        } else {\n            _amount = totalAsset.toAmount(_shares, _roundUp);\n        }\n    }\n\n    /// @notice The ```toAssetShares``` function converts a given asset amount to a number of asset shares (fTokens)\n    /// @param _amount The amount of asset\n    /// @param _roundUp Whether to round up after division\n    /// @param _previewInterest Whether to preview interest accrual before calculation\n    /// @return _shares The number of shares (fTokens)\n    function toAssetShares(\n        uint256 _amount,\n        bool _roundUp,\n        bool _previewInterest\n    ) public view returns (uint256 _shares) {\n        if (_previewInterest) {\n            (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n            _shares = _totalAsset.toShares(_amount, _roundUp);\n        } else {\n            _shares = totalAsset.toShares(_amount, _roundUp);\n        }\n    }\n\n    function convertToAssets(uint256 _shares) external view returns (uint256 _assets) {\n        _assets = toAssetAmount(_shares, false, true);\n    }\n\n    function convertToShares(uint256 _assets) external view returns (uint256 _shares) {\n        _shares = toAssetShares(_assets, false, true);\n    }\n\n    function pricePerShare() external view returns (uint256 _amount) {\n        _amount = toAssetAmount(1e18, false, true);\n    }\n\n    function totalAssets() external view returns (uint256) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        return _totalAsset.amount;\n    }\n\n    function maxDeposit(address _receiver) public view returns (uint256 _maxAssets) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        _maxAssets = _totalAsset.amount >= depositLimit ? 0 : depositLimit - _totalAsset.amount;\n    }\n\n    function maxMint(address _receiver) external view returns (uint256 _maxShares) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        uint256 _maxDeposit = _totalAsset.amount >= depositLimit ? 0 : depositLimit - _totalAsset.amount;\n        _maxShares = _totalAsset.toShares(_maxDeposit, false);\n    }\n\n    function maxWithdraw(address _owner) external view returns (uint256 _maxAssets) {\n        if (isWithdrawPaused) return 0;\n        (\n            ,\n            ,\n            uint256 _feesShare,\n            ,\n            VaultAccount memory _totalAsset,\n            VaultAccount memory _totalBorrow\n        ) = previewAddInterest();\n        // Get the owner balance and include the fees share if owner is this contract\n        uint256 _ownerBalance = _owner == address(this) ? balanceOf(_owner) + _feesShare : balanceOf(_owner);\n\n        // Return the lower of total assets in contract or total assets available to _owner\n        uint256 _totalAssetsAvailable = _totalAssetAvailable(_totalAsset, _totalBorrow);\n        uint256 _totalUserWithdraw = _totalAsset.toAmount(_ownerBalance, false);\n        _maxAssets = _totalAssetsAvailable < _totalUserWithdraw ? _totalAssetsAvailable : _totalUserWithdraw;\n    }\n\n    function maxRedeem(address _owner) external view returns (uint256 _maxShares) {\n        if (isWithdrawPaused) return 0;\n        (\n            ,\n            ,\n            uint256 _feesShare,\n            ,\n            VaultAccount memory _totalAsset,\n            VaultAccount memory _totalBorrow\n        ) = previewAddInterest();\n\n        // Calculate the total shares available\n        uint256 _totalAssetsAvailable = _totalAssetAvailable(_totalAsset, _totalBorrow);\n        uint256 _totalSharesAvailable = _totalAsset.toShares(_totalAssetsAvailable, false);\n\n        // Get the owner balance and include the fees share if owner is this contract\n        uint256 _ownerBalance = _owner == address(this) ? balanceOf(_owner) + _feesShare : balanceOf(_owner);\n        _maxShares = _totalSharesAvailable < _ownerBalance ? _totalSharesAvailable : _ownerBalance;\n    }\n\n    // ============================================================================================\n    // Functions: Configuration\n    // ============================================================================================\n\n    /// @notice The ```SetOracleInfo``` event is emitted when the oracle info (address and max deviation) is set\n    /// @param oldOracle The old oracle address\n    /// @param oldMaxOracleDeviation The old max oracle deviation\n    /// @param newOracle The new oracle address\n    /// @param newMaxOracleDeviation The new max oracle deviation\n    event SetOracleInfo(\n        address oldOracle,\n        uint32 oldMaxOracleDeviation,\n        address newOracle,\n        uint32 newMaxOracleDeviation\n    );\n\n    /// @notice The ```setOracleInfo``` function sets the oracle data\n    /// @param _newOracle The new oracle address\n    /// @param _newMaxOracleDeviation The new max oracle deviation\n    function setOracle(address _newOracle, uint32 _newMaxOracleDeviation) external {\n        _requireTimelock();\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n        emit SetOracleInfo(\n            _exchangeRateInfo.oracle,\n            _exchangeRateInfo.maxOracleDeviation,\n            _newOracle,\n            _newMaxOracleDeviation\n        );\n        _exchangeRateInfo.oracle = _newOracle;\n        _exchangeRateInfo.maxOracleDeviation = _newMaxOracleDeviation;\n        exchangeRateInfo = _exchangeRateInfo;\n    }\n\n    bool public isMaxLTVSetterRevoked;\n\n    /// @notice The ```RevokeMaxLTVSetter``` event is emitted when the max LTV setter is revoked\n    event RevokeMaxLTVSetter();\n\n    /// @notice The ```revokeMaxLTVSetter``` function revokes the max LTV setter\n    function revokeMaxLTVSetter() external {\n        _requireTimelock();\n        isMaxLTVSetterRevoked = true;\n        emit RevokeMaxLTVSetter();\n    }\n\n    /// @notice The ```SetMaxLTV``` event is emitted when the max LTV is set\n    /// @param oldMaxLTV The old max LTV\n    /// @param newMaxLTV The new max LTV\n    event SetMaxLTV(uint256 oldMaxLTV, uint256 newMaxLTV);\n\n    /// @notice The ```setMaxLTV``` function sets the max LTV\n    /// @param _newMaxLTV The new max LTV\n    function setMaxLTV(uint256 _newMaxLTV) external {\n        _requireTimelock();\n        if (isMaxLTVSetterRevoked) revert SetterRevoked();\n        emit SetMaxLTV(maxLTV, _newMaxLTV);\n        maxLTV = _newMaxLTV;\n    }\n\n    /// @notice The ```SetRateContract``` event is emitted when the rate contract is set\n    /// @param oldRateContract The old rate contract\n    /// @param newRateContract The new rate contract\n    event SetRateContract(address oldRateContract, address newRateContract);\n\n    /// @notice The ```setRateContract``` function sets the rate contract address\n    /// @param _newRateContract The new rate contract address\n    function setRateContract(address _newRateContract) external {\n        _requireTimelock();\n        emit SetRateContract(address(rateContract), _newRateContract);\n        rateContract = IRateCalculatorV2(_newRateContract);\n    }\n\n    /// @notice The ```SetLiquidationFees``` event is emitted when the liquidation fees are set\n    /// @param oldCleanLiquidationFee The old clean liquidation fee\n    /// @param oldDirtyLiquidationFee The old dirty liquidation fee\n    /// @param oldProtocolLiquidationFee The old protocol liquidation fee\n    /// @param newCleanLiquidationFee The new clean liquidation fee\n    /// @param newDirtyLiquidationFee The new dirty liquidation fee\n    /// @param newProtocolLiquidationFee The new protocol liquidation fee\n    event SetLiquidationFees(\n        uint256 oldCleanLiquidationFee,\n        uint256 oldDirtyLiquidationFee,\n        uint256 oldProtocolLiquidationFee,\n        uint256 newCleanLiquidationFee,\n        uint256 newDirtyLiquidationFee,\n        uint256 newProtocolLiquidationFee\n    );\n\n    /// @notice The ```setLiquidationFees``` function sets the liquidation fees\n    /// @param _newCleanLiquidationFee The new clean liquidation fee\n    /// @param _newDirtyLiquidationFee The new dirty liquidation fee\n    function setLiquidationFees(\n        uint256 _newCleanLiquidationFee,\n        uint256 _newDirtyLiquidationFee,\n        uint256 _newProtocolLiquidationFee\n    ) external {\n        _requireTimelock();\n        emit SetLiquidationFees(\n            cleanLiquidationFee,\n            dirtyLiquidationFee,\n            protocolLiquidationFee,\n            _newCleanLiquidationFee,\n            _newDirtyLiquidationFee,\n            _newProtocolLiquidationFee\n        );\n        cleanLiquidationFee = _newCleanLiquidationFee;\n        dirtyLiquidationFee = _newDirtyLiquidationFee;\n        protocolLiquidationFee = _newProtocolLiquidationFee;\n    }\n\n    /// @notice The ```ChangeFee``` event first when the fee is changed\n    /// @param newFee The new fee\n    event ChangeFee(uint32 newFee);\n\n    /// @notice The ```changeFee``` function changes the protocol fee, max 50%\n    /// @param _newFee The new fee\n    function changeFee(uint32 _newFee) external {\n        _requireTimelock();\n        if (isInterestPaused) revert InterestPaused();\n        if (_newFee > MAX_PROTOCOL_FEE) {\n            revert BadProtocolFee();\n        }\n        _addInterest();\n        currentRateInfo.feeToProtocolRate = _newFee;\n        emit ChangeFee(_newFee);\n    }\n\n    /// @notice The ```WithdrawFees``` event fires when the fees are withdrawn\n    /// @param shares Number of shares (fTokens) redeemed\n    /// @param recipient To whom the assets were sent\n    /// @param amountToTransfer The amount of fees redeemed\n    event WithdrawFees(uint128 shares, address recipient, uint256 amountToTransfer, uint256 collateralAmount);\n\n    /// @notice The ```withdrawFees``` function withdraws fees accumulated\n    /// @param _shares Number of fTokens to redeem\n    /// @param _recipient Address to send the assets\n    /// @return _amountToTransfer Amount of assets sent to recipient\n    function withdrawFees(uint128 _shares, address _recipient) external onlyOwner returns (uint256 _amountToTransfer) {\n        if (_recipient == address(0)) revert InvalidReceiver();\n\n        // Grab some data from state to save gas\n        VaultAccount memory _totalAsset = totalAsset;\n\n        // Take all available if 0 value passed\n        if (_shares == 0) _shares = uint128(balanceOf(address(this)));\n\n        // We must calculate this before we subtract from _totalAsset or invoke _burn\n        _amountToTransfer = _totalAsset.toAmount(_shares, true);\n\n        _approve(address(this), msg.sender, _shares);\n        _redeem(_totalAsset, _amountToTransfer.toUint128(), _shares, _recipient, address(this));\n        uint256 _collateralAmount = userCollateralBalance[address(this)];\n        _removeCollateral(_collateralAmount, _recipient, address(this));\n        emit WithdrawFees(_shares, _recipient, _amountToTransfer, _collateralAmount);\n    }\n\n    /// @notice The ```SetSwapper``` event fires whenever a swapper is black or whitelisted\n    /// @param swapper The swapper address\n    /// @param approval The approval\n    event SetSwapper(address swapper, bool approval);\n\n    /// @notice The ```setSwapper``` function is called to black or whitelist a given swapper address\n    /// @dev\n    /// @param _swapper The swapper address\n    /// @param _approval The approval\n    function setSwapper(address _swapper, bool _approval) external onlyOwner {\n        swappers[_swapper] = _approval;\n        emit SetSwapper(_swapper, _approval);\n    }\n\n    // ============================================================================================\n    // Functions: Access Control\n    // ============================================================================================\n\n    /// @notice The ```pause``` function is called to pause all contract functionality\n    function pause() external {\n        _requireProtocolOrOwner();\n\n        _setBorrowLimit(0);\n        _setDepositLimit(0);\n        if (!isRepayAccessControlRevoked) _pauseRepay(true);\n        if (!isWithdrawAccessControlRevoked) _pauseWithdraw(true);\n        if (!isLiquidateAccessControlRevoked) _pauseLiquidate(true);\n\n        _addInterest();\n        _pauseInterest(true);\n    }\n\n    /// @notice The ```unpause``` function is called to unpause all contract functionality\n    function unpause() external {\n        _requireTimelockOrOwner();\n\n        _setBorrowLimit(type(uint256).max);\n        _setDepositLimit(type(uint256).max);\n        if (!isRepayAccessControlRevoked) _pauseRepay(false);\n        if (!isWithdrawAccessControlRevoked) _pauseWithdraw(false);\n        if (!isLiquidateAccessControlRevoked) _pauseLiquidate(false);\n\n        _addInterest();\n        _pauseInterest(false);\n    }\n\n    /// @notice The ```pauseBorrow``` function sets borrow limit to 0\n    function pauseBorrow() external {\n        _requireProtocolOrOwner();\n        _setBorrowLimit(0);\n    }\n\n    /// @notice The ```setBorrowLimit``` function sets the borrow limit\n    /// @param _limit The new borrow limit\n    function setBorrowLimit(uint256 _limit) external {\n        _requireTimelockOrOwner();\n        _setBorrowLimit(_limit);\n    }\n\n    /// @notice The ```pauseDeposit``` function pauses deposit functionality\n    function pauseDeposit() external {\n        _requireProtocolOrOwner();\n        _setDepositLimit(0);\n    }\n\n    /// @notice The ```setDepositLimit``` function sets the deposit limit\n    /// @param _limit The new deposit limit\n    function setDepositLimit(uint256 _limit) external {\n        _requireTimelockOrOwner();\n        _setDepositLimit(_limit);\n    }\n\n    /// @notice The ```pauseRepay``` function pauses repay functionality\n    /// @param _isPaused The new pause state\n    function pauseRepay(bool _isPaused) external {\n        if (_isPaused) {\n            _requireProtocolOrOwner();\n        } else {\n            _requireTimelockOrOwner();\n        }\n        if (isRepayAccessControlRevoked) revert AccessControlRevoked();\n        _pauseRepay(_isPaused);\n    }\n\n    /// @notice The ```revokeRepayAccessControl``` function revokes repay access control\n    function revokeRepayAccessControl() external {\n        _requireTimelock();\n        _revokeRepayAccessControl();\n    }\n\n    /// @notice The ```pauseWithdraw``` function pauses withdraw functionality\n    /// @param _isPaused The new pause state\n    function pauseWithdraw(bool _isPaused) external {\n        if (_isPaused) {\n            _requireProtocolOrOwner();\n        } else {\n            _requireTimelockOrOwner();\n        }\n        if (isWithdrawAccessControlRevoked) revert AccessControlRevoked();\n        _pauseWithdraw(_isPaused);\n    }\n\n    /// @notice The ```revokeWithdrawAccessControl``` function revokes withdraw access control\n    function revokeWithdrawAccessControl() external {\n        _requireTimelock();\n        _revokeWithdrawAccessControl();\n    }\n\n    /// @notice The ```pauseLiquidate``` function pauses liquidate functionality\n    /// @param _isPaused The new pause state\n    function pauseLiquidate(bool _isPaused) external {\n        if (_isPaused) {\n            _requireProtocolOrOwner();\n        } else {\n            _requireTimelockOrOwner();\n        }\n        if (isLiquidateAccessControlRevoked) revert AccessControlRevoked();\n        _pauseLiquidate(_isPaused);\n    }\n\n    /// @notice The ```revokeLiquidateAccessControl``` function revokes liquidate access control\n    function revokeLiquidateAccessControl() external {\n        _requireTimelock();\n        _revokeLiquidateAccessControl();\n    }\n\n    /// @notice The ```pauseInterest``` function pauses interest functionality\n    /// @param _isPaused The new pause state\n    function pauseInterest(bool _isPaused) external {\n        if (_isPaused) {\n            _requireProtocolOrOwner();\n        } else {\n            _requireTimelockOrOwner();\n        }\n        // Resets the lastTimestamp which has the effect of no interest accruing over the pause period\n        _addInterest();\n        _pauseInterest(_isPaused);\n    }\n}\n"
      },
      "contracts/src/SturdyPairAccessControl.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ==================== SturdyPairAccessControl =====================\n\nimport { Ownable2Step, Ownable } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport { Timelock2Step } from \"./Timelock2Step.sol\";\nimport { SturdyPairAccessControlErrors } from \"./SturdyPairAccessControlErrors.sol\";\n\n/// @title SturdyPairAccessControl\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  An abstract contract which contains the access control logic for SturdyPair\nabstract contract SturdyPairAccessControl is Timelock2Step, Ownable2Step, SturdyPairAccessControlErrors {\n    // Deployer\n    address public immutable DEPLOYER_ADDRESS;\n\n    // Admin contracts\n    address public circuitBreakerAddress;\n\n    // access control\n    uint256 public borrowLimit = type(uint256).max;\n\n    uint256 public depositLimit = type(uint256).max;\n\n    bool public isRepayPaused;\n    bool public isRepayAccessControlRevoked;\n\n    bool public isWithdrawPaused;\n    bool public isWithdrawAccessControlRevoked;\n\n    bool public isLiquidatePaused;\n    bool public isLiquidateAccessControlRevoked;\n\n    bool public isInterestPaused;\n\n    /// @param _immutables abi.encode(address _circuitBreakerAddress, address _comptrollerAddress, address _timelockAddress)\n    constructor(bytes memory _immutables) Timelock2Step() Ownable2Step() {\n        // Handle Immutables Configuration\n        (address _circuitBreakerAddress, address _comptrollerAddress, address _timelockAddress) = abi.decode(\n            _immutables,\n            (address, address, address)\n        );\n        _setTimelock(_timelockAddress);\n        _transferOwnership(_comptrollerAddress);\n\n        // Deployer contract\n        DEPLOYER_ADDRESS = msg.sender;\n        circuitBreakerAddress = _circuitBreakerAddress;\n    }\n\n    // ============================================================================================\n    // Functions: Access Control\n    // ============================================================================================\n\n    function _requireProtocolOrOwner() internal view {\n        if (\n            msg.sender != circuitBreakerAddress &&\n            msg.sender != owner() &&\n            msg.sender != DEPLOYER_ADDRESS &&\n            msg.sender != timelockAddress\n        ) {\n            revert OnlyProtocolOrOwner();\n        }\n    }\n\n    function _requireTimelockOrOwner() internal view {\n        if (msg.sender != owner() && msg.sender != timelockAddress) {\n            revert OnlyTimelockOrOwner();\n        }\n    }\n\n    /// @notice The ```SetBorrowLimit``` event is emitted when the borrow limit is set\n    /// @param limit The new borrow limit\n    event SetBorrowLimit(uint256 limit);\n\n    function _setBorrowLimit(uint256 _limit) internal {\n        borrowLimit = _limit;\n        emit SetBorrowLimit(_limit);\n    }\n\n    /// @notice The ```SetDepositLimit``` event is emitted when the deposit limit is set\n    /// @param limit The new deposit limit\n    event SetDepositLimit(uint256 limit);\n\n    function _setDepositLimit(uint256 _limit) internal {\n        depositLimit = _limit;\n        emit SetDepositLimit(_limit);\n    }\n\n    /// @notice The ```RevokeRepayAccessControl``` event is emitted when repay access control is revoked\n    event RevokeRepayAccessControl();\n\n    function _revokeRepayAccessControl() internal {\n        isRepayAccessControlRevoked = true;\n        emit RevokeRepayAccessControl();\n    }\n\n    /// @notice The ```PauseRepay``` event is emitted when repay is paused or unpaused\n    /// @param isPaused The new paused state\n    event PauseRepay(bool isPaused);\n\n    function _pauseRepay(bool _isPaused) internal {\n        isRepayPaused = _isPaused;\n        emit PauseRepay(_isPaused);\n    }\n\n    /// @notice The ```RevokeWithdrawAccessControl``` event is emitted when withdraw access control is revoked\n    event RevokeWithdrawAccessControl();\n\n    function _revokeWithdrawAccessControl() internal {\n        isWithdrawAccessControlRevoked = true;\n        emit RevokeWithdrawAccessControl();\n    }\n\n    /// @notice The ```PauseWithdraw``` event is emitted when withdraw is paused or unpaused\n    /// @param isPaused The new paused state\n    event PauseWithdraw(bool isPaused);\n\n    function _pauseWithdraw(bool _isPaused) internal {\n        isWithdrawPaused = _isPaused;\n        emit PauseWithdraw(_isPaused);\n    }\n\n    /// @notice The ```RevokeLiquidateAccessControl``` event is emitted when liquidate access control is revoked\n    event RevokeLiquidateAccessControl();\n\n    function _revokeLiquidateAccessControl() internal {\n        isLiquidateAccessControlRevoked = true;\n        emit RevokeLiquidateAccessControl();\n    }\n\n    /// @notice The ```PauseLiquidate``` event is emitted when liquidate is paused or unpaused\n    /// @param isPaused The new paused state\n    event PauseLiquidate(bool isPaused);\n\n    function _pauseLiquidate(bool _isPaused) internal {\n        isLiquidatePaused = _isPaused;\n        emit PauseLiquidate(_isPaused);\n    }\n\n    /// @notice The ```PauseInterest``` event is emitted when interest is paused or unpaused\n    /// @param isPaused The new paused state\n    event PauseInterest(bool isPaused);\n\n    function _pauseInterest(bool _isPaused) internal {\n        isInterestPaused = _isPaused;\n        emit PauseInterest(_isPaused);\n    }\n\n    /// @notice The ```SetCircuitBreaker``` event is emitted when the circuit breaker address is set\n    /// @param oldCircuitBreaker The old circuit breaker address\n    /// @param newCircuitBreaker The new circuit breaker address\n    event SetCircuitBreaker(address oldCircuitBreaker, address newCircuitBreaker);\n\n    /// @notice The ```_setCircuitBreaker``` function is called to set the circuit breaker address\n    /// @param _newCircuitBreaker The new circuit breaker address\n    function _setCircuitBreaker(address _newCircuitBreaker) internal {\n        address oldCircuitBreaker = circuitBreakerAddress;\n        circuitBreakerAddress = _newCircuitBreaker;\n        emit SetCircuitBreaker(oldCircuitBreaker, _newCircuitBreaker);\n    }\n\n    /// @notice The ```setCircuitBreaker``` function is called to set the circuit breaker address\n    /// @param _newCircuitBreaker The new circuit breaker address\n    function setCircuitBreaker(address _newCircuitBreaker) external virtual {\n        _requireTimelock();\n        _setCircuitBreaker(_newCircuitBreaker);\n    }\n}\n"
      },
      "contracts/src/SturdyPairAccessControlErrors.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ================ SturdyPairAccessControlErrors ===================\n\n/// @title SturdyPairAccessControlErrors\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  An abstract contract which contains the errors for the Access Control contract\nabstract contract SturdyPairAccessControlErrors {\n    error OnlyProtocolOrOwner();\n    error OnlyTimelockOrOwner();\n    error ExceedsBorrowLimit();\n    error AccessControlRevoked();\n    error RepayPaused();\n    error ExceedsDepositLimit();\n    error WithdrawPaused();\n    error LiquidatePaused();\n    error InterestPaused();\n}\n"
      },
      "contracts/src/SturdyPairConstants.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ===================== SturdyPairConstants ========================\n\n/// @title SturdyPairConstants\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  An abstract contract which contains the errors and constants for the SturdyPair contract\nabstract contract SturdyPairConstants {\n    // ============================================================================================\n    // Constants\n    // ============================================================================================\n\n    // Precision settings\n    uint256 internal constant LTV_PRECISION = 1e5; // 5 decimals\n    uint256 internal constant LIQ_PRECISION = 1e5;\n    uint256 internal constant UTIL_PREC = 1e5;\n    uint256 internal constant FEE_PRECISION = 1e5;\n    uint256 internal constant EXCHANGE_PRECISION = 1e18;\n    uint256 internal constant DEVIATION_PRECISION = 1e5;\n    uint256 internal constant RATE_PRECISION = 1e18;\n\n    // Protocol Fee\n    uint256 internal constant MAX_PROTOCOL_FEE = 5e4; // 50% 1e5 precision\n\n    error Insolvent(uint256 _borrow, uint256 _collateral, uint256 _exchangeRate);\n    error BorrowerSolvent();\n    error InsufficientAssetsInContract(uint256 _assets, uint256 _request);\n    error SlippageTooHigh(uint256 _minOut, uint256 _actual);\n    error BadSwapper();\n    error InvalidPath(address _expected, address _actual);\n    error BadProtocolFee();\n    error PastDeadline(uint256 _blockTimestamp, uint256 _deadline);\n    error SetterRevoked();\n    error ExceedsMaxOracleDeviation();\n    error InvalidReceiver();\n    error InvalidOnBehalfOf();\n    error InvalidApproveBorrowDelegation();\n    error InvalidBorrower();\n    error InvalidDelegator();\n}\n"
      },
      "contracts/src/SturdyPairCore.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ========================= SturdyPairCore =========================\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SturdyPairAccessControl } from \"./SturdyPairAccessControl.sol\";\nimport { SturdyPairConstants } from \"./SturdyPairConstants.sol\";\nimport { VaultAccount, VaultAccountingLibrary } from \"./libraries/VaultAccount.sol\";\nimport { SafeERC20 } from \"./libraries/SafeERC20.sol\";\nimport { IDualOracle } from \"./interfaces/IDualOracle.sol\";\nimport { IRateCalculatorV2 } from \"./interfaces/IRateCalculatorV2.sol\";\nimport { ISwapper } from \"./interfaces/ISwapper.sol\";\n\n/// @title SturdyPairCore\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  An abstract contract which contains the core logic and storage for the SturdyPair\nabstract contract SturdyPairCore is SturdyPairAccessControl, SturdyPairConstants, ERC20, ReentrancyGuard {\n    using VaultAccountingLibrary for VaultAccount;\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n\n    function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {\n        _major = 3;\n        _minor = 0;\n        _patch = 0;\n    }\n\n    // ============================================================================================\n    // Settings set by constructor()\n    // ============================================================================================\n\n    // Asset and collateral contracts\n    IERC20 internal immutable assetContract;\n    IERC20 public immutable collateralContract;\n\n    // LTV Settings\n    /// @notice The maximum LTV allowed for this pair\n    /// @dev 1e5 precision\n    uint256 public maxLTV;\n\n    // Liquidation Fees\n    /// @notice The liquidation fee, given as a % of repayment amount, when all collateral is consumed in liquidation\n    /// @dev 1e5 precision\n    uint256 public cleanLiquidationFee;\n    /// @notice The liquidation fee, given as % of repayment amount, when some collateral remains for borrower\n    /// @dev 1e5 precision\n    uint256 public dirtyLiquidationFee;\n    /// @notice The portion of the liquidation fee given to protocol\n    /// @dev 1e5 precision\n    uint256 public protocolLiquidationFee;\n\n    // Interest Rate Calculator Contract\n    IRateCalculatorV2 public rateContract; // For complex rate calculations\n\n    // Swapper\n    mapping(address => bool) public swappers; // approved swapper addresses\n\n    // ERC20 Metadata\n    string internal nameOfContract;\n    string internal symbolOfContract;\n    uint8 internal immutable decimalsOfContract;\n\n    // ============================================================================================\n    // Storage\n    // ============================================================================================\n\n    /// @notice Stores information about the current interest rate\n    /// @dev struct is packed to reduce SLOADs. feeToProtocolRate is 1e5 precision, ratePerSec & fullUtilizationRate is 1e18 precision\n    CurrentRateInfo public currentRateInfo;\n\n    struct CurrentRateInfo {\n        uint32 lastBlock;\n        uint32 feeToProtocolRate; // Fee amount 1e5 precision\n        uint64 lastTimestamp;\n        uint64 ratePerSec;\n        uint64 fullUtilizationRate;\n    }\n\n    /// @notice Stores information about the current exchange rate. Collateral:Asset ratio\n    /// @dev Struct packed to save SLOADs. Amount of Collateral Token to buy 1e18 Asset Token\n    ExchangeRateInfo public exchangeRateInfo;\n\n    struct ExchangeRateInfo {\n        address oracle;\n        uint32 maxOracleDeviation; // % of larger number, 1e5 precision\n        uint184 lastTimestamp;\n        uint256 lowExchangeRate;\n        uint256 highExchangeRate;\n    }\n\n    // Contract Level Accounting\n    VaultAccount public totalAsset; // amount = total amount of assets, shares = total shares outstanding\n    VaultAccount public totalBorrow; // amount = total borrow amount with interest accrued, shares = total shares outstanding\n    uint256 public totalCollateral; // total amount of collateral in contract\n\n    // User Level Accounting\n    /// @notice Stores the balance of collateral for each user\n    mapping(address => uint256) public userCollateralBalance; // amount of collateral each user is backed\n    /// @notice Stores the balance of borrow shares for each user\n    mapping(address => uint256) public userBorrowShares; // represents the shares held by individuals\n    /// @notice Stores the borrow allowance of the user\n    mapping(address => mapping(address => uint256)) public userBorrowAllowances;  // represent the borrowable amount on behalfof user\n    /// @notice Stores the whitelisted delegators who call the removeCollateralFrom(), ex: Leverage contracts\n    mapping(address => bool) public whitelistedDelegators;  // represent the leverage contract who call the removeCollateralFrom()\n\n    // NOTE: user shares of assets are represented as ERC-20 tokens and accessible via balanceOf()\n\n    // ============================================================================================\n    // Constructor\n    // ============================================================================================\n\n    /// @notice The ```constructor``` function is called on deployment\n    /// @param _configData abi.encode(address _asset, address _collateral, address _oracle, uint32 _maxOracleDeviation, address _rateContract, uint64 _fullUtilizationRate, uint256 _maxLTV, uint256 _cleanLiquidationFee, uint256 _dirtyLiquidationFee, uint256 _protocolLiquidationFee)\n    /// @param _immutables abi.encode(address _circuitBreakerAddress, address _comptrollerAddress, address _timelockAddress)\n    /// @param _customConfigData abi.encode(string memory _nameOfContract, string memory _symbolOfContract, uint8 _decimalsOfContract)\n    constructor(\n        bytes memory _configData,\n        bytes memory _immutables,\n        bytes memory _customConfigData\n    ) SturdyPairAccessControl(_immutables) ERC20(\"\", \"\") {\n        {\n            (\n                address _asset,\n                address _collateral,\n                address _oracle,\n                uint32 _maxOracleDeviation,\n                address _rateContract,\n                uint64 _fullUtilizationRate,\n                uint256 _maxLTV,\n                uint256 _liquidationFee,\n                uint256 _protocolLiquidationFee\n            ) = abi.decode(\n                    _configData,\n                    (address, address, address, uint32, address, uint64, uint256, uint256, uint256)\n                );\n\n            // Pair Settings\n            assetContract = IERC20(_asset);\n            collateralContract = IERC20(_collateral);\n\n            currentRateInfo.feeToProtocolRate = 0;\n            currentRateInfo.fullUtilizationRate = _fullUtilizationRate;\n            currentRateInfo.lastTimestamp = uint64(block.timestamp - 1);\n            currentRateInfo.lastBlock = uint32(block.number - 1);\n\n            exchangeRateInfo.oracle = _oracle;\n            exchangeRateInfo.maxOracleDeviation = _maxOracleDeviation;\n\n            rateContract = IRateCalculatorV2(_rateContract);\n\n            //Liquidation Fee Settings\n            cleanLiquidationFee = _liquidationFee;\n            dirtyLiquidationFee = (_liquidationFee * 90_000) / LIQ_PRECISION; // 90% of clean fee\n            protocolLiquidationFee = _protocolLiquidationFee;\n\n            // set maxLTV\n            maxLTV = _maxLTV;\n        }\n\n        {\n            (string memory _nameOfContract, string memory _symbolOfContract, uint8 _decimalsOfContract) = abi.decode(\n                _customConfigData,\n                (string, string, uint8)\n            );\n\n            // ERC20 Metadata\n            nameOfContract = _nameOfContract;\n            symbolOfContract = _symbolOfContract;\n            decimalsOfContract = _decimalsOfContract;\n\n            // Instantiate Interest\n            _addInterest();\n            // Instantiate Exchange Rate\n            _updateExchangeRate();\n        }\n    }\n\n    // ============================================================================================\n    // Internal Helpers\n    // ============================================================================================\n\n    /// @notice The ```_totalAssetAvailable``` function returns the total balance of Asset Tokens in the contract\n    /// @param _totalAsset VaultAccount struct which stores total amount and shares for assets\n    /// @param _totalBorrow VaultAccount struct which stores total amount and shares for borrows\n    /// @return The balance of Asset Tokens held by contract\n    function _totalAssetAvailable(\n        VaultAccount memory _totalAsset,\n        VaultAccount memory _totalBorrow\n    ) internal pure returns (uint256) {\n        return _totalAsset.amount - _totalBorrow.amount;\n    }\n\n    /// @notice The ```_isSolvent``` function determines if a given borrower is solvent given an exchange rate\n    /// @param _borrower The borrower address to check\n    /// @param _exchangeRate The exchange rate, i.e. the amount of collateral to buy 1e18 asset\n    /// @return Whether borrower is solvent\n    function _isSolvent(address _borrower, uint256 _exchangeRate) internal view returns (bool) {\n        if (maxLTV == 0) return true;\n        uint256 _borrowerAmount = totalBorrow.toAmount(userBorrowShares[_borrower], true);\n        if (_borrowerAmount == 0) return true;\n        uint256 _collateralAmount = userCollateralBalance[_borrower];\n        if (_collateralAmount == 0) return false;\n\n        uint256 _ltv = (((_borrowerAmount * _exchangeRate) / EXCHANGE_PRECISION) * LTV_PRECISION) / _collateralAmount;\n        return _ltv <= maxLTV;\n    }\n\n    // ============================================================================================\n    // Modifiers\n    // ============================================================================================\n\n    /// @notice Checks for solvency AFTER executing contract code\n    /// @param _borrower The borrower whose solvency we will check\n    modifier isSolvent(address _borrower) {\n        _;\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n\n        if (!_isSolvent(_borrower, exchangeRateInfo.highExchangeRate)) {\n            revert Insolvent(\n                totalBorrow.toAmount(userBorrowShares[_borrower], true),\n                userCollateralBalance[_borrower],\n                exchangeRateInfo.highExchangeRate\n            );\n        }\n    }\n\n    // ============================================================================================\n    // Functions: Interest Accumulation and Adjustment\n    // ============================================================================================\n\n    /// @notice The ```AddInterest``` event is emitted when interest is accrued by borrowers\n    /// @param interestEarned The total interest accrued by all borrowers\n    /// @param rate The interest rate used to calculate accrued interest\n    /// @param feesAmount The amount of fees paid to protocol\n    /// @param feesShare The amount of shares distributed to protocol\n    event AddInterest(uint256 interestEarned, uint256 rate, uint256 feesAmount, uint256 feesShare);\n\n    /// @notice The ```UpdateRate``` event is emitted when the interest rate is updated\n    /// @param oldRatePerSec The old interest rate (per second)\n    /// @param oldFullUtilizationRate The old full utilization rate\n    /// @param newRatePerSec The new interest rate (per second)\n    /// @param newFullUtilizationRate The new full utilization rate\n    event UpdateRate(\n        uint256 oldRatePerSec,\n        uint256 oldFullUtilizationRate,\n        uint256 newRatePerSec,\n        uint256 newFullUtilizationRate\n    );\n\n    /// @notice The ```addInterest``` function is a public implementation of _addInterest and allows 3rd parties to trigger interest accrual\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _feesAmount The amount of fees paid to protocol\n    /// @return _feesShare The amount of shares distributed to protocol\n    /// @return _currentRateInfo The new rate info struct\n    /// @return _totalAsset The new total asset struct\n    /// @return _totalBorrow The new total borrow struct\n    function addInterest(\n        bool _returnAccounting\n    )\n        external\n        nonReentrant\n        returns (\n            uint256 _interestEarned,\n            uint256 _feesAmount,\n            uint256 _feesShare,\n            CurrentRateInfo memory _currentRateInfo,\n            VaultAccount memory _totalAsset,\n            VaultAccount memory _totalBorrow\n        )\n    {\n        (, _interestEarned, _feesAmount, _feesShare, _currentRateInfo) = _addInterest();\n        if (_returnAccounting) {\n            _totalAsset = totalAsset;\n            _totalBorrow = totalBorrow;\n        }\n    }\n\n    /// @notice The ```previewAddInterest``` function\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _feesAmount The amount of fees paid to protocol\n    /// @return _feesShare The amount of shares distributed to protocol\n    /// @return _newCurrentRateInfo The new rate info struct\n    /// @return _totalAsset The new total asset struct\n    /// @return _totalBorrow The new total borrow struct\n    function previewAddInterest()\n        public\n        view\n        returns (\n            uint256 _interestEarned,\n            uint256 _feesAmount,\n            uint256 _feesShare,\n            CurrentRateInfo memory _newCurrentRateInfo,\n            VaultAccount memory _totalAsset,\n            VaultAccount memory _totalBorrow\n        )\n    {\n        _newCurrentRateInfo = currentRateInfo;\n        // Write return values\n        InterestCalculationResults memory _results = _calculateInterest(_newCurrentRateInfo);\n\n        if (_results.isInterestUpdated) {\n            _interestEarned = _results.interestEarned;\n            _feesAmount = _results.feesAmount;\n            _feesShare = _results.feesShare;\n\n            _newCurrentRateInfo.ratePerSec = _results.newRate;\n            _newCurrentRateInfo.fullUtilizationRate = _results.newFullUtilizationRate;\n\n            _totalAsset = _results.totalAsset;\n            _totalBorrow = _results.totalBorrow;\n        } else {\n            _totalAsset = totalAsset;\n            _totalBorrow = totalBorrow;\n        }\n    }\n\n    struct InterestCalculationResults {\n        bool isInterestUpdated;\n        uint64 newRate;\n        uint64 newFullUtilizationRate;\n        uint256 interestEarned;\n        uint256 feesAmount;\n        uint256 feesShare;\n        VaultAccount totalAsset;\n        VaultAccount totalBorrow;\n    }\n\n    /// @notice The ```_calculateInterest``` function calculates the interest to be accrued and the new interest rate info\n    /// @param _currentRateInfo The current rate info\n    /// @return _results The results of the interest calculation\n    function _calculateInterest(\n        CurrentRateInfo memory _currentRateInfo\n    ) internal view returns (InterestCalculationResults memory _results) {\n        // Short circuit if interest already calculated this block OR if interest is paused\n        if (_currentRateInfo.lastTimestamp != block.timestamp && !isInterestPaused) {\n            // Indicate that interest is updated and calculated\n            _results.isInterestUpdated = true;\n\n            // Write return values and use these to save gas\n            _results.totalAsset = totalAsset;\n            _results.totalBorrow = totalBorrow;\n\n            // Time elapsed since last interest update\n            uint256 _deltaTime = block.timestamp - _currentRateInfo.lastTimestamp;\n\n            // Get the utilization rate\n            uint256 _utilizationRate = _results.totalAsset.amount == 0\n                ? 0\n                : (UTIL_PREC * _results.totalBorrow.amount) / _results.totalAsset.amount;\n\n            // Request new interest rate and full utilization rate from the rate calculator\n            (_results.newRate, _results.newFullUtilizationRate) = IRateCalculatorV2(rateContract).getNewRate(\n                _deltaTime,\n                _utilizationRate,\n                _currentRateInfo.fullUtilizationRate\n            );\n\n            // Calculate interest accrued\n            _results.interestEarned = (_deltaTime * _results.totalBorrow.amount * _results.newRate) / RATE_PRECISION;\n\n            // Accrue interest (if any) and fees iff no overflow\n            if (\n                _results.interestEarned > 0 &&\n                _results.interestEarned + _results.totalBorrow.amount <= type(uint128).max &&\n                _results.interestEarned + _results.totalAsset.amount <= type(uint128).max\n            ) {\n                // Increment totalBorrow and totalAsset by interestEarned\n                _results.totalBorrow.amount += uint128(_results.interestEarned);\n                _results.totalAsset.amount += uint128(_results.interestEarned);\n                if (_currentRateInfo.feeToProtocolRate > 0) {\n                    _results.feesAmount =\n                        (_results.interestEarned * _currentRateInfo.feeToProtocolRate) /\n                        FEE_PRECISION;\n\n                    _results.feesShare =\n                        (_results.feesAmount * _results.totalAsset.shares) /\n                        (_results.totalAsset.amount - _results.feesAmount);\n\n                    // Effects: Give new shares to this contract, effectively diluting lenders an amount equal to the fees\n                    // We can safely cast because _feesShare < _feesAmount < interestEarned which is always less than uint128\n                    _results.totalAsset.shares += uint128(_results.feesShare);\n                }\n            }\n        }\n    }\n\n    /// @notice The ```_addInterest``` function is invoked prior to every external function and is used to accrue interest and update interest rate\n    /// @dev Can only called once per block\n    /// @return _isInterestUpdated True if interest was calculated\n    /// @return _interestEarned The amount of interest accrued by all borrowers\n    /// @return _feesAmount The amount of fees paid to protocol\n    /// @return _feesShare The amount of shares distributed to protocol\n    /// @return _currentRateInfo The new rate info struct\n    function _addInterest()\n        internal\n        returns (\n            bool _isInterestUpdated,\n            uint256 _interestEarned,\n            uint256 _feesAmount,\n            uint256 _feesShare,\n            CurrentRateInfo memory _currentRateInfo\n        )\n    {\n        // Pull from storage and set default return values\n        _currentRateInfo = currentRateInfo;\n\n        // Calc interest\n        InterestCalculationResults memory _results = _calculateInterest(_currentRateInfo);\n\n        // Write return values only if interest was updated and calculated\n        if (_results.isInterestUpdated) {\n            _isInterestUpdated = _results.isInterestUpdated;\n            _interestEarned = _results.interestEarned;\n            _feesAmount = _results.feesAmount;\n            _feesShare = _results.feesShare;\n\n            // emit here so that we have access to the old values\n            emit UpdateRate(\n                _currentRateInfo.ratePerSec,\n                _currentRateInfo.fullUtilizationRate,\n                _results.newRate,\n                _results.newFullUtilizationRate\n            );\n            emit AddInterest(_interestEarned, _results.newRate, _feesAmount, _feesShare);\n\n            // overwrite original values\n            _currentRateInfo.ratePerSec = _results.newRate;\n            _currentRateInfo.fullUtilizationRate = _results.newFullUtilizationRate;\n            _currentRateInfo.lastTimestamp = uint64(block.timestamp);\n            _currentRateInfo.lastBlock = uint32(block.number);\n\n            // Effects: write to state\n            currentRateInfo = _currentRateInfo;\n            totalAsset = _results.totalAsset;\n            totalBorrow = _results.totalBorrow;\n            if (_feesShare > 0) _mint(address(this), _feesShare);\n        }\n    }\n\n    // ============================================================================================\n    // Functions: ExchangeRate\n    // ============================================================================================\n\n    /// @notice The ```UpdateExchangeRate``` event is emitted when the Collateral:Asset exchange rate is updated\n    /// @param lowExchangeRate The low exchange rate\n    /// @param highExchangeRate The high exchange rate\n    event UpdateExchangeRate(uint256 lowExchangeRate, uint256 highExchangeRate);\n\n    /// @notice The ```WarnOracleData``` event is emitted when one of the oracles has stale or otherwise problematic data\n    /// @param oracle The oracle address\n    event WarnOracleData(address oracle);\n\n    /// @notice The ```updateExchangeRate``` function is the external implementation of _updateExchangeRate.\n    /// @dev This function is invoked at most once per block as these queries can be expensive\n    /// @return _isBorrowAllowed True if deviation is within bounds\n    /// @return _lowExchangeRate The low exchange rate\n    /// @return _highExchangeRate The high exchange rate\n    function updateExchangeRate()\n        external\n        nonReentrant\n        returns (bool _isBorrowAllowed, uint256 _lowExchangeRate, uint256 _highExchangeRate)\n    {\n        return _updateExchangeRate();\n    }\n\n    /// @notice The ```_updateExchangeRate``` function retrieves the latest exchange rate. i.e how much collateral to buy 1e18 asset.\n    /// @dev This function is invoked at most once per block as these queries can be expensive\n    /// @return _isBorrowAllowed True if deviation is within bounds\n    /// @return _lowExchangeRate The low exchange rate\n    /// @return _highExchangeRate The high exchange rate\n\n    function _updateExchangeRate()\n        internal\n        returns (bool _isBorrowAllowed, uint256 _lowExchangeRate, uint256 _highExchangeRate)\n    {\n        // Pull from storage to save gas and set default return values\n        ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;\n\n        // Short circuit if already updated this block\n        if (_exchangeRateInfo.lastTimestamp != block.timestamp) {\n            // Get the latest exchange rate from the dual oracle\n            bool _oneOracleBad;\n            (_oneOracleBad, _lowExchangeRate, _highExchangeRate) = IDualOracle(_exchangeRateInfo.oracle).getPrices();\n\n            // If one oracle is bad data, emit an event for off-chain monitoring\n            if (_oneOracleBad) emit WarnOracleData(_exchangeRateInfo.oracle);\n\n            // Effects: Bookkeeping and write to storage\n            _exchangeRateInfo.lastTimestamp = uint184(block.timestamp);\n            _exchangeRateInfo.lowExchangeRate = _lowExchangeRate;\n            _exchangeRateInfo.highExchangeRate = _highExchangeRate;\n            exchangeRateInfo = _exchangeRateInfo;\n            emit UpdateExchangeRate(_lowExchangeRate, _highExchangeRate);\n        } else {\n            // Use default return values if already updated this block\n            _lowExchangeRate = _exchangeRateInfo.lowExchangeRate;\n            _highExchangeRate = _exchangeRateInfo.highExchangeRate;\n        }\n\n        uint256 _deviation = (DEVIATION_PRECISION *\n            (_exchangeRateInfo.highExchangeRate - _exchangeRateInfo.lowExchangeRate)) /\n            _exchangeRateInfo.highExchangeRate;\n        if (_deviation <= _exchangeRateInfo.maxOracleDeviation) {\n            _isBorrowAllowed = true;\n        }\n    }\n\n    // ============================================================================================\n    // Functions: Lending\n    // ============================================================================================\n\n    /// @notice The ```Deposit``` event fires when a user deposits assets to the pair\n    /// @param caller the msg.sender\n    /// @param owner the account the fTokens are sent to\n    /// @param assets the amount of assets deposited\n    /// @param shares the number of fTokens minted\n    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);\n\n    /// @notice The ```_deposit``` function is the internal implementation for lending assets\n    /// @dev Caller must invoke ```ERC20.approve``` on the Asset Token contract prior to calling function\n    /// @param _totalAsset An in memory VaultAccount struct representing the total amounts and shares for the Asset Token\n    /// @param _amount The amount of Asset Token to be transferred\n    /// @param _shares The amount of Asset Shares (fTokens) to be minted\n    /// @param _receiver The address to receive the Asset Shares (fTokens)\n    function _deposit(VaultAccount memory _totalAsset, uint128 _amount, uint128 _shares, address _receiver) internal {\n        // Effects: bookkeeping\n        _totalAsset.amount += _amount;\n        _totalAsset.shares += _shares;\n\n        // Effects: write back to storage\n        _mint(_receiver, _shares);\n        totalAsset = _totalAsset;\n\n        // Interactions\n        assetContract.safeTransferFrom(msg.sender, address(this), _amount);\n        emit Deposit(msg.sender, _receiver, _amount, _shares);\n    }\n\n    function previewDeposit(uint256 _assets) external view returns (uint256 _sharesReceived) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        _sharesReceived = _totalAsset.toShares(_assets, false);\n    }\n\n    /// @notice The ```deposit``` function allows a user to Lend Assets by specifying the amount of Asset Tokens to lend\n    /// @dev Caller must invoke ```ERC20.approve``` on the Asset Token contract prior to calling function\n    /// @param _amount The amount of Asset Token to transfer to Pair\n    /// @param _receiver The address to receive the Asset Shares (fTokens)\n    /// @return _sharesReceived The number of fTokens received for the deposit\n    function deposit(uint256 _amount, address _receiver) external nonReentrant returns (uint256 _sharesReceived) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Pull from storage to save gas\n        VaultAccount memory _totalAsset = totalAsset;\n\n        // Check if this deposit will violate the deposit limit\n        if (depositLimit < _totalAsset.amount + _amount) revert ExceedsDepositLimit();\n\n        // Calculate the number of fTokens to mint\n        _sharesReceived = _totalAsset.toShares(_amount, false);\n\n        // Execute the deposit effects\n        _deposit(_totalAsset, _amount.toUint128(), _sharesReceived.toUint128(), _receiver);\n    }\n\n    function previewMint(uint256 _shares) external view returns (uint256 _amount) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        _amount = _totalAsset.toAmount(_shares, false);\n    }\n\n    function mint(uint256 _shares, address _receiver) external nonReentrant returns (uint256 _amount) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Pull from storage to save gas\n        VaultAccount memory _totalAsset = totalAsset;\n\n        // Calculate the number of assets to transfer based on the shares to mint\n        _amount = _totalAsset.toAmount(_shares, false);\n\n        // Check if this deposit will violate the deposit limit\n        if (depositLimit < _totalAsset.amount + _amount) revert ExceedsDepositLimit();\n\n        // Execute the deposit effects\n        _deposit(_totalAsset, _amount.toUint128(), _shares.toUint128(), _receiver);\n    }\n\n    /// @notice The ```Withdraw``` event fires when a user redeems their fTokens for the underlying asset\n    /// @param caller the msg.sender\n    /// @param receiver The address to which the underlying asset will be transferred to\n    /// @param owner The owner of the fTokens\n    /// @param assets The assets transferred\n    /// @param shares The number of fTokens burned\n    event Withdraw(\n        address indexed caller,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /// @notice The ```_redeem``` function is an internal implementation which allows a Lender to pull their Asset Tokens out of the Pair\n    /// @dev Caller must invoke ```ERC20.approve``` on the Asset Token contract prior to calling function\n    /// @param _totalAsset An in-memory VaultAccount struct which holds the total amount of Asset Tokens and the total number of Asset Shares (fTokens)\n    /// @param _amountToReturn The number of Asset Tokens to return\n    /// @param _shares The number of Asset Shares (fTokens) to burn\n    /// @param _receiver The address to which the Asset Tokens will be transferred\n    /// @param _owner The owner of the Asset Shares (fTokens)\n    function _redeem(\n        VaultAccount memory _totalAsset,\n        uint128 _amountToReturn,\n        uint128 _shares,\n        address _receiver,\n        address _owner\n    ) internal {\n        // Check for sufficient allowance/approval if necessary\n        if (msg.sender != _owner) {\n            uint256 allowed = allowance(_owner, msg.sender);\n            // NOTE: This will revert on underflow ensuring that allowance > shares\n            if (allowed != type(uint256).max) _approve(_owner, msg.sender, allowed - _shares);\n        }\n\n        // Check for sufficient withdraw liquidity (not strictly necessary because balance will underflow)\n        uint256 _assetsAvailable = _totalAssetAvailable(_totalAsset, totalBorrow);\n        if (_assetsAvailable < _amountToReturn) {\n            revert InsufficientAssetsInContract(_assetsAvailable, _amountToReturn);\n        }\n\n        // Effects: bookkeeping\n        _totalAsset.amount -= _amountToReturn;\n        _totalAsset.shares -= _shares;\n\n        // Effects: write to storage\n        totalAsset = _totalAsset;\n        _burn(_owner, _shares);\n\n        // Interactions\n        assetContract.safeTransfer(_receiver, _amountToReturn);\n        emit Withdraw(msg.sender, _receiver, _owner, _amountToReturn, _shares);\n    }\n\n    function previewRedeem(uint256 _shares) external view returns (uint256 _assets) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        _assets = _totalAsset.toAmount(_shares, false);\n    }\n\n    /// @notice The ```redeem``` function allows the caller to redeem their Asset Shares for Asset Tokens\n    /// @param _shares The number of Asset Shares (fTokens) to burn for Asset Tokens\n    /// @param _receiver The address to which the Asset Tokens will be transferred\n    /// @param _owner The owner of the Asset Shares (fTokens)\n    /// @return _amountToReturn The amount of Asset Tokens to be transferred\n    function redeem(\n        uint256 _shares,\n        address _receiver,\n        address _owner\n    ) external nonReentrant returns (uint256 _amountToReturn) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Check if withdraw is paused and revert if necessary\n        if (isWithdrawPaused) revert WithdrawPaused();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Pull from storage to save gas\n        VaultAccount memory _totalAsset = totalAsset;\n\n        // Calculate the number of assets to transfer based on the shares to burn\n        _amountToReturn = _totalAsset.toAmount(_shares, false);\n\n        // Execute the withdraw effects\n        _redeem(_totalAsset, _amountToReturn.toUint128(), _shares.toUint128(), _receiver, _owner);\n    }\n\n    /// @notice The ```previewWithdraw``` function returns the number of Asset Shares (fTokens) that would be burned for a given amount of Asset Tokens\n    /// @param _amount The amount of Asset Tokens to be withdrawn\n    /// @return _sharesToBurn The number of shares that would be burned\n    function previewWithdraw(uint256 _amount) external view returns (uint256 _sharesToBurn) {\n        (, , , , VaultAccount memory _totalAsset, ) = previewAddInterest();\n        _sharesToBurn = _totalAsset.toShares(_amount, true);\n    }\n\n    /// @notice The ```withdraw``` function allows the caller to withdraw their Asset Tokens for a given amount of fTokens\n    /// @param _amount The amount to withdraw\n    /// @param _receiver The address to which the Asset Tokens will be transferred\n    /// @param _owner The owner of the Asset Shares (fTokens)\n    /// @return _sharesToBurn The number of shares (fTokens) that were burned\n    function withdraw(\n        uint256 _amount,\n        address _receiver,\n        address _owner\n    ) external nonReentrant returns (uint256 _sharesToBurn) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Check if withdraw is paused and revert if necessary\n        if (isWithdrawPaused) revert WithdrawPaused();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Pull from storage to save gas\n        VaultAccount memory _totalAsset = totalAsset;\n\n        // Calculate the number of shares to burn based on the amount to withdraw\n        _sharesToBurn = _totalAsset.toShares(_amount, true);\n\n        // Execute the withdraw effects\n        _redeem(_totalAsset, _amount.toUint128(), _sharesToBurn.toUint128(), _receiver, _owner);\n    }\n\n    // ============================================================================================\n    // Functions: Borrowing\n    // ============================================================================================\n\n    /// @notice The ```BorrowAsset``` event is emitted when a borrower increases their position\n    /// @param _borrower The borrower whose account was debited\n    /// @param _receiver The address to which the Asset Tokens were transferred\n    /// @param _borrowAmount The amount of Asset Tokens transferred\n    /// @param _sharesAdded The number of Borrow Shares the borrower was debited\n    event BorrowAsset(\n        address indexed _borrower,\n        address indexed _receiver,\n        uint256 _borrowAmount,\n        uint256 _sharesAdded\n    );\n\n    /// @notice The ```_borrowAsset``` function is the internal implementation for borrowing assets\n    /// @param _borrowAmount The amount of the Asset Token to borrow\n    /// @param _receiver The address to receive the Asset Tokens\n    /// @return _sharesAdded The amount of borrow shares the msg.sender will be debited\n    function _borrowAsset(uint128 _borrowAmount, address _receiver) internal returns (uint256 _sharesAdded) {\n        // Get borrow accounting from storage to save gas\n        VaultAccount memory _totalBorrow = totalBorrow;\n\n        // Check available capital (not strictly necessary because balance will underflow, but better revert message)\n        uint256 _assetsAvailable = _totalAssetAvailable(totalAsset, _totalBorrow);\n        if (_assetsAvailable < _borrowAmount) {\n            revert InsufficientAssetsInContract(_assetsAvailable, _borrowAmount);\n        }\n\n        // Calculate the number of shares to add based on the amount to borrow\n        _sharesAdded = _totalBorrow.toShares(_borrowAmount, true);\n\n        // Effects: Bookkeeping to add shares & amounts to total Borrow accounting\n        _totalBorrow.amount += _borrowAmount;\n        _totalBorrow.shares += uint128(_sharesAdded);\n        // NOTE: we can safely cast here because shares are always less than amount and _borrowAmount is uint128\n\n        // Effects: write back to storage\n        totalBorrow = _totalBorrow;\n        userBorrowShares[msg.sender] += _sharesAdded;\n\n        // Interactions\n        if (_receiver != address(this)) {\n            assetContract.safeTransfer(_receiver, _borrowAmount);\n        }\n        emit BorrowAsset(msg.sender, _receiver, _borrowAmount, _sharesAdded);\n    }\n\n    /// @notice The ```_borrowAssetOnBehalfOf``` function is the internal implementation for borrowing assets on behalf of borrower\n    /// @dev msg.sender will receive the Asset Tokens\n    /// @param _borrowAmount The amount of the Asset Token to borrow\n    /// @param _onBehalfOf The address which will receive the debt. Should be the address of the borrower itself\n    /// @return _sharesAdded The amount of borrow shares the _onBehalfOf will be debited\n    function _borrowAssetOnBehalfOf(uint128 _borrowAmount, address _onBehalfOf) internal returns (uint256 _sharesAdded) {\n        // Get borrow accounting from storage to save gas\n        VaultAccount memory _totalBorrow = totalBorrow;\n\n        // Check available capital (not strictly necessary because balance will underflow, but better revert message)\n        uint256 _assetsAvailable = _totalAssetAvailable(totalAsset, _totalBorrow);\n        if (_assetsAvailable < _borrowAmount) {\n            revert InsufficientAssetsInContract(_assetsAvailable, _borrowAmount);\n        }\n\n        // decrease borrowAllowance (borrowing power)\n        uint256 newAllowance = userBorrowAllowances[_onBehalfOf][msg.sender] - _borrowAmount;\n        userBorrowAllowances[_onBehalfOf][msg.sender] = newAllowance;\n        emit UserBorrowAllowanceDelegated(_onBehalfOf, msg.sender, newAllowance);\n\n        // Calculate the number of shares to add based on the amount to borrow\n        _sharesAdded = _totalBorrow.toShares(_borrowAmount, true);\n\n        // Effects: Bookkeeping to add shares & amounts to total Borrow accounting\n        _totalBorrow.amount += _borrowAmount;\n        _totalBorrow.shares += uint128(_sharesAdded);\n        // NOTE: we can safely cast here because shares are always less than amount and _borrowAmount is uint128\n\n        // Effects: write back to storage\n        totalBorrow = _totalBorrow;\n        userBorrowShares[_onBehalfOf] += _sharesAdded;\n\n        // Interactions\n        assetContract.safeTransfer(msg.sender, _borrowAmount);\n\n        emit BorrowAsset(_onBehalfOf, msg.sender, _borrowAmount, _sharesAdded);\n    }\n\n    /// @notice The ```borrowAsset``` function allows a user to open/increase a borrow position\n    /// @dev Borrower must call ```ERC20.approve``` on the Collateral Token contract if applicable\n    /// @param _borrowAmount The amount of Asset Token to borrow\n    /// @param _collateralAmount The amount of Collateral Token to transfer to Pair\n    /// @param _receiver The address which will receive the Asset Tokens\n    /// @return _shares The number of borrow Shares the msg.sender will be debited\n    function borrowAsset(\n        uint256 _borrowAmount,\n        uint256 _collateralAmount,\n        address _receiver\n    ) external nonReentrant isSolvent(msg.sender) returns (uint256 _shares) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Check if borrow will violate the borrow limit and revert if necessary\n        if (borrowLimit < totalBorrow.amount + _borrowAmount) revert ExceedsBorrowLimit();\n\n        // Update _exchangeRate and check if borrow is allowed based on deviation\n        (bool _isBorrowAllowed, , ) = _updateExchangeRate();\n        if (!_isBorrowAllowed) revert ExceedsMaxOracleDeviation();\n\n        // Only add collateral if necessary\n        if (_collateralAmount > 0) {\n            _addCollateral(msg.sender, _collateralAmount, msg.sender);\n        }\n\n        // Effects: Call internal borrow function\n        _shares = _borrowAsset(_borrowAmount.toUint128(), _receiver);\n    }\n\n    /// @notice The ```borrowAssetOnBehalfOf``` function allows a user to open/increase a borrow position on behalf of borrower\n    /// @dev msg.sender will receive the Asset Tokens\n    /// @param _borrowAmount The amount of Asset Token to borrow\n    /// @param _onBehalfOf The address which will receive the debt. Should be the address of the borrower itself\n    /// @return _shares The number of borrow Shares the _onBehalfOf will be debited\n    function borrowAssetOnBehalfOf(\n        uint256 _borrowAmount,\n        address _onBehalfOf\n    ) external nonReentrant isSolvent(_onBehalfOf) returns (uint256 _shares) {\n        if (_onBehalfOf == address(0) || msg.sender == _onBehalfOf) revert InvalidOnBehalfOf();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Check if borrow will violate the borrow limit and revert if necessary\n        if (borrowLimit < totalBorrow.amount + _borrowAmount) revert ExceedsBorrowLimit();\n\n        // Update _exchangeRate and check if borrow is allowed based on deviation\n        (bool _isBorrowAllowed, , ) = _updateExchangeRate();\n        if (!_isBorrowAllowed) revert ExceedsMaxOracleDeviation();\n\n        // Effects: Call internal borrow function\n        _shares = _borrowAssetOnBehalfOf(_borrowAmount.toUint128(), _onBehalfOf);\n    }\n\n    /// @notice The ```UserBorrowAllowanceDelegated``` event is emitted when a borrower delegates borrowing power to a user\n    /// @param _fromUser The borrower who delegates borrowing power\n    /// @param _toUser The user who receive the borrowing power from borrower\n    /// @param _amount The max amount being delegated\n    event UserBorrowAllowanceDelegated(\n        address indexed _fromUser,\n        address indexed _toUser,\n        uint256 _amount\n    );\n\n    /// @notice The ```approveBorrowDelegation``` function delegates borrowing power to a user\n    /// @param _delegatee the address receiving the delegated borrowing power\n    /// @param _amount the maximum amount being delegated.\n    function approveBorrowDelegation(address _delegatee, uint256 _amount) external {\n        // To change the approve amount you first have to reduce the addresses`\n        //  allowance to zero by calling `approveBorrowDelegation(_delegatee, 0)` if it is not\n        //  already 0 to mitigate the race condition described here:\n        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n        if ((_amount != 0) && (userBorrowAllowances[msg.sender][_delegatee] != 0)) {\n            revert InvalidApproveBorrowDelegation();\n        }\n\n        userBorrowAllowances[msg.sender][_delegatee] = _amount;\n        emit UserBorrowAllowanceDelegated(msg.sender, _delegatee, _amount);\n    }\n\n    /// @notice The ```AddCollateral``` event is emitted when a borrower adds collateral to their position\n    /// @param sender The source of funds for the new collateral\n    /// @param borrower The borrower account for which the collateral should be credited\n    /// @param collateralAmount The amount of Collateral Token to be transferred\n    event AddCollateral(address indexed sender, address indexed borrower, uint256 collateralAmount);\n\n    /// @notice The ```_addCollateral``` function is an internal implementation for adding collateral to a borrowers position\n    /// @param _sender The source of funds for the new collateral\n    /// @param _collateralAmount The amount of Collateral Token to be transferred\n    /// @param _borrower The borrower account for which the collateral should be credited\n    function _addCollateral(address _sender, uint256 _collateralAmount, address _borrower) internal {\n        // Effects: write to state\n        userCollateralBalance[_borrower] += _collateralAmount;\n        totalCollateral += _collateralAmount;\n\n        // Interactions\n        if (_sender != address(this)) {\n            collateralContract.safeTransferFrom(_sender, address(this), _collateralAmount);\n        }\n        emit AddCollateral(_sender, _borrower, _collateralAmount);\n    }\n\n    /// @notice The ```addCollateral``` function allows the caller to add Collateral Token to a borrowers position\n    /// @dev msg.sender must call ERC20.approve() on the Collateral Token contract prior to invocation\n    /// @param _collateralAmount The amount of Collateral Token to be added to borrower's position\n    /// @param _borrower The account to be credited\n    function addCollateral(uint256 _collateralAmount, address _borrower) external nonReentrant {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n        _addCollateral(msg.sender, _collateralAmount, _borrower);\n    }\n\n    /// @notice The ```RemoveCollateral``` event is emitted when collateral is removed from a borrower's position\n    /// @param _sender The account from which funds are transferred\n    /// @param _collateralAmount The amount of Collateral Token to be transferred\n    /// @param _receiver The address to which Collateral Tokens will be transferred\n    event RemoveCollateral(\n        address indexed _sender,\n        uint256 _collateralAmount,\n        address indexed _receiver,\n        address indexed _borrower\n    );\n\n    /// @notice The ```_removeCollateral``` function is the internal implementation for removing collateral from a borrower's position\n    /// @param _collateralAmount The amount of Collateral Token to remove from the borrower's position\n    /// @param _receiver The address to receive the Collateral Token transferred\n    /// @param _borrower The borrower whose account will be debited the Collateral amount\n    function _removeCollateral(uint256 _collateralAmount, address _receiver, address _borrower) internal {\n        // Effects: write to state\n        // NOTE: Following line will revert on underflow if _collateralAmount > userCollateralBalance\n        userCollateralBalance[_borrower] -= _collateralAmount;\n        // NOTE: Following line will revert on underflow if totalCollateral < _collateralAmount\n        totalCollateral -= _collateralAmount;\n\n        // Interactions\n        if (_receiver != address(this)) {\n            collateralContract.safeTransfer(_receiver, _collateralAmount);\n        }\n        emit RemoveCollateral(msg.sender, _collateralAmount, _receiver, _borrower);\n    }\n\n    /// @notice The ```removeCollateral``` function is used to remove collateral from msg.sender's borrow position\n    /// @dev msg.sender must be solvent after invocation or transaction will revert\n    /// @param _collateralAmount The amount of Collateral Token to transfer\n    /// @param _receiver The address to receive the transferred funds\n    function removeCollateral(\n        uint256 _collateralAmount,\n        address _receiver\n    ) external nonReentrant isSolvent(msg.sender) {\n        if (_receiver == address(0)) revert InvalidReceiver();\n\n        _addInterest();\n        // Note: exchange rate is irrelevant when borrower has no debt shares\n        if (userBorrowShares[msg.sender] > 0) {\n            (bool _isBorrowAllowed, , ) = _updateExchangeRate();\n            if (!_isBorrowAllowed) revert ExceedsMaxOracleDeviation();\n        }\n        _removeCollateral(_collateralAmount, _receiver, msg.sender);\n    }\n\n    /// @notice The ```SetWhitelistedDelegators``` event is emitted when admin enable/disable delegator who can call removeCollateralFrom()\n    /// @param _delegator the address of contract who can call the removeCollateralFrom()\n    /// @param _enabled the enable/disable flag.\n    event SetWhitelistedDelegators(\n        address indexed _delegator,\n        bool _enabled\n    );\n\n    /// @notice The ```setWhitelistedDelegators``` function enable/disable the delegators who can call the removeCollateralFrom()\n    /// @param _delegator the address of contract who can call the removeCollateralFrom()\n    /// @param _enabled the enable/disable flag.\n    function setWhitelistedDelegators(address _delegator, bool _enabled) external payable onlyOwner {\n        whitelistedDelegators[_delegator] = _enabled;\n        emit SetWhitelistedDelegators(_delegator, _enabled);\n    }\n\n    /// @notice The ```removeCollateralFrom``` function is used to remove collateral from the borrower\n    /// @dev caller must be delegator(ex: leverage contract) and borrower must be solvent after invocation or transaction will revert\n    /// @param _collateralAmount The amount of Collateral Token to transfer\n    /// @param _receiver The address to receive the transferred funds\n    /// @param _borrower The address removing collateral from\n    function removeCollateralFrom(\n        uint256 _collateralAmount,\n        address _receiver,\n        address _borrower\n    ) external payable nonReentrant isSolvent(_borrower) {\n        if(whitelistedDelegators[msg.sender] == false) revert InvalidDelegator();\n        if (_receiver == address(0)) revert InvalidReceiver();\n        if (_borrower == address(0)) revert InvalidBorrower();\n\n        _addInterest();\n        // Note: exchange rate is irrelevant when borrower has no debt shares\n        if (userBorrowShares[_borrower] > 0) {\n            (bool _isBorrowAllowed, , ) = _updateExchangeRate();\n            if (!_isBorrowAllowed) revert ExceedsMaxOracleDeviation();\n        }\n        _removeCollateral(_collateralAmount, _receiver, _borrower);\n    }\n\n    /// @notice The ```RepayAsset``` event is emitted whenever a debt position is repaid\n    /// @param payer The address paying for the repayment\n    /// @param borrower The borrower whose account will be credited\n    /// @param amountToRepay The amount of Asset token to be transferred\n    /// @param shares The amount of Borrow Shares which will be debited from the borrower after repayment\n    event RepayAsset(address indexed payer, address indexed borrower, uint256 amountToRepay, uint256 shares);\n\n    /// @notice The ```_repayAsset``` function is the internal implementation for repaying a borrow position\n    /// @dev The payer must have called ERC20.approve() on the Asset Token contract prior to invocation\n    /// @param _totalBorrow An in memory copy of the totalBorrow VaultAccount struct\n    /// @param _amountToRepay The amount of Asset Token to transfer\n    /// @param _shares The number of Borrow Shares the sender is repaying\n    /// @param _payer The address from which funds will be transferred\n    /// @param _borrower The borrower account which will be credited\n    function _repayAsset(\n        VaultAccount memory _totalBorrow,\n        uint128 _amountToRepay,\n        uint128 _shares,\n        address _payer,\n        address _borrower\n    ) internal {\n        // Effects: Bookkeeping\n        _totalBorrow.amount -= _amountToRepay;\n        _totalBorrow.shares -= _shares;\n\n        // Effects: write to state\n        userBorrowShares[_borrower] -= _shares;\n        totalBorrow = _totalBorrow;\n\n        // Interactions\n        if (_payer != address(this)) {\n            assetContract.safeTransferFrom(_payer, address(this), _amountToRepay);\n        }\n        emit RepayAsset(_payer, _borrower, _amountToRepay, _shares);\n    }\n\n    /// @notice The ```repayAsset``` function allows the caller to pay down the debt for a given borrower.\n    /// @dev Caller must first invoke ```ERC20.approve()``` for the Asset Token contract\n    /// @param _shares The number of Borrow Shares which will be repaid by the call\n    /// @param _borrower The account for which the debt will be reduced\n    /// @return _amountToRepay The amount of Asset Tokens which were transferred in order to repay the Borrow Shares\n    function repayAsset(uint256 _shares, address _borrower) external nonReentrant returns (uint256 _amountToRepay) {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        // Check if repay is paused revert if necessary\n        if (isRepayPaused) revert RepayPaused();\n\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Calculate amount to repay based on shares\n        VaultAccount memory _totalBorrow = totalBorrow;\n        _amountToRepay = _totalBorrow.toAmount(_shares, true);\n\n        // Execute repayment effects\n        _repayAsset(_totalBorrow, _amountToRepay.toUint128(), _shares.toUint128(), msg.sender, _borrower);\n    }\n\n    // ============================================================================================\n    // Functions: Liquidations\n    // ============================================================================================\n    /// @notice The ```Liquidate``` event is emitted when a liquidation occurs\n    /// @param _borrower The borrower account for which the liquidation occurred\n    /// @param _collateralForLiquidator The amount of Collateral Token transferred to the liquidator\n    /// @param _sharesToLiquidate The number of Borrow Shares the liquidator repaid on behalf of the borrower\n    /// @param _sharesToAdjust The number of Borrow Shares that were adjusted on liabilities and assets (a writeoff)\n    event Liquidate(\n        address indexed _borrower,\n        uint256 _collateralForLiquidator,\n        uint256 _sharesToLiquidate,\n        uint256 _amountLiquidatorToRepay,\n        uint256 _feesAmount,\n        uint256 _sharesToAdjust,\n        uint256 _amountToAdjust\n    );\n\n    /// @notice The ```liquidate``` function allows a third party to repay a borrower's debt if they have become insolvent\n    /// @dev Caller must invoke ```ERC20.approve``` on the Asset Token contract prior to calling ```Liquidate()```\n    /// @param _sharesToLiquidate The number of Borrow Shares repaid by the liquidator\n    /// @param _deadline The timestamp after which tx will revert\n    /// @param _borrower The account for which the repayment is credited and from whom collateral will be taken\n    /// @return _collateralForLiquidator The amount of Collateral Token transferred to the liquidator\n    function liquidate(\n        uint128 _sharesToLiquidate,\n        uint256 _deadline,\n        address _borrower\n    ) external nonReentrant returns (uint256 _collateralForLiquidator) {\n        if (_borrower == address(0)) revert InvalidReceiver();\n\n        // Check if liquidate is paused revert if necessary\n        if (isLiquidatePaused) revert LiquidatePaused();\n\n        // Ensure deadline has not passed\n        if (block.timestamp > _deadline) revert PastDeadline(block.timestamp, _deadline);\n\n        // accrue interest if necessary\n        _addInterest();\n\n        // Update exchange rate and use the lower rate for liquidations\n        (, uint256 _exchangeRate, ) = _updateExchangeRate();\n\n        // Check if borrower is solvent, revert if they are\n        if (_isSolvent(_borrower, _exchangeRate)) {\n            revert BorrowerSolvent();\n        }\n\n        // Read from state\n        VaultAccount memory _totalBorrow = totalBorrow;\n        uint256 _userCollateralBalance = userCollateralBalance[_borrower];\n        uint128 _borrowerShares = userBorrowShares[_borrower].toUint128();\n\n        // Prevent stack-too-deep\n        int256 _leftoverCollateral;\n        uint256 _feesAmount;\n        {\n            // Checks & Calculations\n            // Determine the liquidation amount in collateral units (i.e. how much debt liquidator is going to repay)\n            uint256 _liquidationAmountInCollateralUnits = ((_totalBorrow.toAmount(_sharesToLiquidate, false) *\n                _exchangeRate) / EXCHANGE_PRECISION);\n\n            // We first optimistically calculate the amount of collateral to give the liquidator based on the higher clean liquidation fee\n            // This fee only applies if the liquidator does a full liquidation\n            uint256 _optimisticCollateralForLiquidator = (_liquidationAmountInCollateralUnits *\n                (LIQ_PRECISION + cleanLiquidationFee)) / LIQ_PRECISION;\n\n            // Because interest accrues every block, _liquidationAmountInCollateralUnits from a few lines up is an ever increasing value\n            // This means that leftoverCollateral can occasionally go negative by a few hundred wei (cleanLiqFee premium covers this for liquidator)\n            _leftoverCollateral = (_userCollateralBalance.toInt256() - _optimisticCollateralForLiquidator.toInt256());\n\n            // If cleanLiquidation fee results in no leftover collateral, give liquidator all the collateral\n            // This will only be true when there liquidator is cleaning out the position\n            _collateralForLiquidator = _leftoverCollateral <= 0\n                ? _userCollateralBalance\n                : (_liquidationAmountInCollateralUnits * (LIQ_PRECISION + dirtyLiquidationFee)) / LIQ_PRECISION;\n\n            if (protocolLiquidationFee > 0) {\n                _feesAmount = (protocolLiquidationFee * _collateralForLiquidator) / LIQ_PRECISION;\n                _collateralForLiquidator = _collateralForLiquidator - _feesAmount;\n            }\n        }\n\n        // Calculated here for use during repayment, grouped with other calcs before effects start\n        uint128 _amountLiquidatorToRepay = (_totalBorrow.toAmount(_sharesToLiquidate, true)).toUint128();\n\n        // Determine if and how much debt to adjust\n        uint128 _sharesToAdjust = 0;\n        {\n            uint128 _amountToAdjust = 0;\n            if (_leftoverCollateral <= 0) {\n                // Determine if we need to adjust any shares\n                _sharesToAdjust = _borrowerShares - _sharesToLiquidate;\n                if (_sharesToAdjust > 0) {\n                    // Write off bad debt\n                    _amountToAdjust = (_totalBorrow.toAmount(_sharesToAdjust, false)).toUint128();\n\n                    // Note: Ensure this memory struct will be passed to _repayAsset for write to state\n                    _totalBorrow.amount -= _amountToAdjust;\n\n                    // Effects: write to state\n                    totalAsset.amount -= _amountToAdjust;\n                }\n            }\n            emit Liquidate(\n                _borrower,\n                _collateralForLiquidator,\n                _sharesToLiquidate,\n                _amountLiquidatorToRepay,\n                _feesAmount,\n                _sharesToAdjust,\n                _amountToAdjust\n            );\n        }\n\n        // Effects & Interactions\n        // NOTE: reverts if _shares > userBorrowShares\n        _repayAsset(\n            _totalBorrow,\n            _amountLiquidatorToRepay,\n            _sharesToLiquidate + _sharesToAdjust,\n            msg.sender,\n            _borrower\n        ); // liquidator repays shares on behalf of borrower\n        // NOTE: reverts if _collateralForLiquidator > userCollateralBalance\n        // Collateral is removed on behalf of borrower and sent to liquidator\n        // NOTE: reverts if _collateralForLiquidator > userCollateralBalance\n        _removeCollateral(_collateralForLiquidator, msg.sender, _borrower);\n        // Adjust bookkeeping only (decreases collateral held by borrower)\n        _removeCollateral(_feesAmount, address(this), _borrower);\n        // Adjusts bookkeeping only (increases collateral held by protocol)\n        _addCollateral(address(this), _feesAmount, address(this));\n    }\n\n    // ============================================================================================\n    // Functions: Leverage\n    // ============================================================================================\n\n    /// @notice The ```RepayAssetWithCollateral``` event is emitted whenever ```repayAssetWithCollateral()``` is invoked\n    /// @param _borrower The borrower account for which the repayment is taking place\n    /// @param _swapperAddress The address of the whitelisted swapper to use for token swaps\n    /// @param _collateralToSwap The amount of Collateral Token to swap and use for repayment\n    /// @param _amountAssetOut The amount of Asset Token which was repaid\n    /// @param _sharesRepaid The number of Borrow Shares which were repaid\n    event RepayAssetWithCollateral(\n        address indexed _borrower,\n        address _swapperAddress,\n        uint256 _collateralToSwap,\n        uint256 _amountAssetOut,\n        uint256 _sharesRepaid\n    );\n\n    /// @notice The ```repayAssetWithCollateral``` function allows a borrower to repay their debt using existing collateral in contract\n    /// @param _swapperAddress The address of the whitelisted swapper to use for token swaps\n    /// @param _collateralToSwap The amount of Collateral Tokens to swap for Asset Tokens\n    /// @param _amountAssetOutMin The minimum amount of Asset Tokens to receive during the swap\n    /// @param _path An array containing the addresses of ERC20 tokens to swap.  Adheres to UniV2 style path params.\n    /// @return _amountAssetOut The amount of Asset Tokens received for the Collateral Tokens, the amount the borrowers account was credited\n    function repayAssetWithCollateral(\n        address _swapperAddress,\n        uint256 _collateralToSwap,\n        uint256 _amountAssetOutMin,\n        address[] calldata _path\n    ) external nonReentrant isSolvent(msg.sender) returns (uint256 _amountAssetOut) {\n        // Accrue interest if necessary\n        _addInterest();\n\n        // Update exchange rate and check if borrow is allowed, revert if not\n        (bool _isBorrowAllowed, , ) = _updateExchangeRate();\n        if (!_isBorrowAllowed) revert ExceedsMaxOracleDeviation();\n\n        IERC20 _assetContract = assetContract;\n        IERC20 _collateralContract = collateralContract;\n\n        if (!swappers[_swapperAddress]) {\n            revert BadSwapper();\n        }\n        if (_path[0] != address(_collateralContract)) {\n            revert InvalidPath(address(_collateralContract), _path[0]);\n        }\n        if (_path[_path.length - 1] != address(_assetContract)) {\n            revert InvalidPath(address(_assetContract), _path[_path.length - 1]);\n        }\n\n        // Effects: bookkeeping & write to state\n        // Debit users collateral balance in preparation for swap, setting _recipient to address(this) means no transfer occurs\n        _removeCollateral(_collateralToSwap, address(this), msg.sender);\n\n        // Interactions\n        _collateralContract.approve(_swapperAddress, _collateralToSwap);\n\n        // Even though swappers are trusted, we verify the balance before and after swap\n        uint256 _initialAssetBalance = _assetContract.balanceOf(address(this));\n        ISwapper(_swapperAddress).swapExactTokensForTokens(\n            _collateralToSwap,\n            _amountAssetOutMin,\n            _path,\n            address(this),\n            block.timestamp\n        );\n        uint256 _finalAssetBalance = _assetContract.balanceOf(address(this));\n\n        // Note: VIOLATES CHECKS-EFFECTS-INTERACTION pattern, make sure function is NONREENTRANT\n        // Effects: bookkeeping\n        _amountAssetOut = _finalAssetBalance - _initialAssetBalance;\n        if (_amountAssetOut < _amountAssetOutMin) {\n            revert SlippageTooHigh(_amountAssetOutMin, _amountAssetOut);\n        }\n\n        VaultAccount memory _totalBorrow = totalBorrow;\n        uint256 _sharesToRepay = _totalBorrow.toShares(_amountAssetOut, false);\n\n        // Effects: write to state\n        // Note: setting _payer to address(this) means no actual transfer will occur.  Contract already has funds\n        _repayAsset(_totalBorrow, _amountAssetOut.toUint128(), _sharesToRepay.toUint128(), address(this), msg.sender);\n\n        emit RepayAssetWithCollateral(msg.sender, _swapperAddress, _collateralToSwap, _amountAssetOut, _sharesToRepay);\n    }\n}\n"
      },
      "contracts/src/SturdyPairDeployer.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ====================== SturdyPairDeployer ========================\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport { SSTORE2 } from \"@rari-capital/solmate/src/utils/SSTORE2.sol\";\nimport { BytesLib } from \"solidity-bytes-utils/contracts/BytesLib.sol\";\nimport { ISturdyWhitelist } from \"./interfaces/ISturdyWhitelist.sol\";\nimport { ISturdyPair } from \"./interfaces/ISturdyPair.sol\";\nimport { ISturdyPairRegistry } from \"./interfaces/ISturdyPairRegistry.sol\";\nimport { SafeERC20 } from \"./libraries/SafeERC20.sol\";\n\n// solhint-disable no-inline-assembly\n\nstruct ConstructorParams {\n    address circuitBreaker;\n    address comptroller;\n    address timelock;\n    address sturdyWhitelist;\n    address sturdyPairRegistry;\n}\n\n/// @title SturdyPairDeployer\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice Deploys and initializes new SturdyPairs\n/// @dev Uses create2 to deploy the pairs, logs an event, and records a list of all deployed pairs\ncontract SturdyPairDeployer is Ownable {\n    using Strings for uint256;\n    using SafeERC20 for IERC20;\n\n    // Storage\n    address public contractAddress1;\n    address public contractAddress2;\n\n    // Admin contracts\n    address public circuitBreakerAddress;\n    address public comptrollerAddress;\n    address public timelockAddress;\n    address public sturdyPairRegistryAddress;\n    address public sturdyWhitelistAddress;\n\n    // Default swappers\n    address[] public defaultSwappers;\n\n    /// @notice Emits when a new pair is deployed\n    /// @notice The ```LogDeploy``` event is emitted when a new Pair is deployed\n    /// @param address_ The address of the pair\n    /// @param asset The address of the Asset Token contract\n    /// @param collateral The address of the Collateral Token contract\n    /// @param name The name of the Pair\n    /// @param configData The config data of the Pair\n    /// @param immutables The immutables of the Pair\n    /// @param customConfigData The custom config data of the Pair\n    event LogDeploy(\n        address indexed address_,\n        address indexed asset,\n        address indexed collateral,\n        string name,\n        bytes configData,\n        bytes immutables,\n        bytes customConfigData\n    );\n\n    /// @notice List of the names of all deployed Pairs\n    address[] public deployedPairsArray;\n\n    constructor(ConstructorParams memory _params) Ownable() {\n        circuitBreakerAddress = _params.circuitBreaker;\n        comptrollerAddress = _params.comptroller;\n        timelockAddress = _params.timelock;\n        sturdyWhitelistAddress = _params.sturdyWhitelist;\n        sturdyPairRegistryAddress = _params.sturdyPairRegistry;\n    }\n\n    function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {\n        return (4, 1, 0);\n    }\n\n    // ============================================================================================\n    // Functions: View Functions\n    // ============================================================================================\n\n    /// @notice The ```deployedPairsLength``` function returns the length of the deployedPairsArray\n    /// @return length of array\n    function deployedPairsLength() external view returns (uint256) {\n        return deployedPairsArray.length;\n    }\n\n    /// @notice The ```getAllPairAddresses``` function returns all pair addresses in deployedPairsArray\n    /// @return _deployedPairs memory All deployed pair addresses\n    function getAllPairAddresses() external view returns (address[] memory _deployedPairs) {\n        _deployedPairs = deployedPairsArray;\n    }\n\n    function getNextNameSymbol(\n        address _asset,\n        address _collateral\n    ) public view returns (string memory _name, string memory _symbol) {\n        uint256 _length = ISturdyPairRegistry(sturdyPairRegistryAddress).deployedPairsLength();\n        _name = string(\n            abi.encodePacked(\n                \"Sturdy Interest Bearing \",\n                IERC20(_asset).safeSymbol(),\n                \" (\",\n                IERC20(_collateral).safeName(),\n                \")\",\n                \" - \",\n                (_length + 1).toString()\n            )\n        );\n        _symbol = string(\n            abi.encodePacked(\n                \"f\",\n                IERC20(_asset).safeSymbol(),\n                \"(\",\n                IERC20(_collateral).safeSymbol(),\n                \")\",\n                \"-\",\n                (_length + 1).toString()\n            )\n        );\n    }\n\n    // ============================================================================================\n    // Functions: Setters\n    // ============================================================================================\n\n    /// @notice The ```setCreationCode``` function sets the bytecode for the sturdyPair\n    /// @dev splits the data if necessary to accommodate creation code that is slightly larger than 24kb\n    /// @param _creationCode The creationCode for the Sturdy Pair\n    function setCreationCode(bytes calldata _creationCode) external onlyOwner {\n        bytes memory _firstHalf = BytesLib.slice(_creationCode, 0, 13_000);\n        contractAddress1 = SSTORE2.write(_firstHalf);\n        if (_creationCode.length > 13_000) {\n            bytes memory _secondHalf = BytesLib.slice(_creationCode, 13_000, _creationCode.length - 13_000);\n            contractAddress2 = SSTORE2.write(_secondHalf);\n        }\n    }\n\n    /// @notice The ```setDefaultSwappers``` function is used to set default list of approved swappers\n    /// @param _swappers The list of swappers to set as default allowed\n    function setDefaultSwappers(address[] memory _swappers) external onlyOwner {\n        defaultSwappers = _swappers;\n    }\n\n    /// @notice The ```SetTimelock``` event is emitted when the timelockAddress is set\n    /// @param oldAddress The original address\n    /// @param newAddress The new address\n    event SetTimelock(address oldAddress, address newAddress);\n\n    /// @notice The ```setTimelock``` function sets the timelockAddress\n    /// @param _newAddress the new time lock address\n    function setTimelock(address _newAddress) external onlyOwner {\n        emit SetTimelock(timelockAddress, _newAddress);\n        timelockAddress = _newAddress;\n    }\n\n    /// @notice The ```SetRegistry``` event is emitted when the sturdyPairRegistryAddress is set\n    /// @param oldAddress The old address\n    /// @param newAddress The new address\n    event SetRegistry(address oldAddress, address newAddress);\n\n    /// @notice The ```setRegistry``` function sets the sturdyPairRegistryAddress\n    /// @param _newAddress The new address\n    function setRegistry(address _newAddress) external onlyOwner {\n        emit SetRegistry(sturdyPairRegistryAddress, _newAddress);\n        sturdyPairRegistryAddress = _newAddress;\n    }\n\n    /// @notice The ```SetComptroller``` event is emitted when the comptrollerAddress is set\n    /// @param oldAddress The old address\n    /// @param newAddress The new address\n    event SetComptroller(address oldAddress, address newAddress);\n\n    /// @notice The ```setComptroller``` function sets the comptrollerAddress\n    /// @param _newAddress The new address\n    function setComptroller(address _newAddress) external onlyOwner {\n        emit SetComptroller(comptrollerAddress, _newAddress);\n        comptrollerAddress = _newAddress;\n    }\n\n    /// @notice The ```SetWhitelist``` event is emitted when the sturdyWhitelistAddress is set\n    /// @param oldAddress The old address\n    /// @param newAddress The new address\n    event SetWhitelist(address oldAddress, address newAddress);\n\n    /// @notice The ```setWhitelist``` function sets the sturdyWhitelistAddress\n    /// @param _newAddress The new address\n    function setWhitelist(address _newAddress) external onlyOwner {\n        emit SetWhitelist(sturdyWhitelistAddress, _newAddress);\n        sturdyWhitelistAddress = _newAddress;\n    }\n\n    /// @notice The ```SetCircuitBreaker``` event is emitted when the circuitBreakerAddress is set\n    /// @param oldAddress The old address\n    /// @param newAddress The new address\n    event SetCircuitBreaker(address oldAddress, address newAddress);\n\n    /// @notice The ```setCircuitBreaker``` function sets the circuitBreakerAddress\n    /// @param _newAddress The new address\n    function setCircuitBreaker(address _newAddress) external onlyOwner {\n        emit SetCircuitBreaker(circuitBreakerAddress, _newAddress);\n        circuitBreakerAddress = _newAddress;\n    }\n\n    // ============================================================================================\n    // Functions: Internal Methods\n    // ============================================================================================\n\n    /// @notice The ```_deploy``` function is an internal function with deploys the pair\n    /// @param _configData abi.encode(address _asset, address _collateral, address _oracle, uint32 _maxOracleDeviation, address _rateContract, uint64 _fullUtilizationRate, uint256 _maxLTV, uint256 _cleanLiquidationFee, uint256 _dirtyLiquidationFee, uint256 _protocolLiquidationFee)\n    /// @param _immutables abi.encode(address _circuitBreakerAddress, address _comptrollerAddress, address _timelockAddress)\n    /// @param _customConfigData abi.encode(string memory _nameOfContract, string memory _symbolOfContract, uint8 _decimalsOfContract)\n    /// @return _pairAddress The address to which the Pair was deployed\n    function _deploy(\n        bytes memory _configData,\n        bytes memory _immutables,\n        bytes memory _customConfigData\n    ) private returns (address _pairAddress) {\n        // Get creation code\n        bytes memory _creationCode = BytesLib.concat(SSTORE2.read(contractAddress1), SSTORE2.read(contractAddress2));\n\n        // Get bytecode\n        bytes memory bytecode = abi.encodePacked(\n            _creationCode,\n            abi.encode(_configData, _immutables, _customConfigData)\n        );\n\n        // Generate salt using constructor params\n        bytes32 salt = keccak256(abi.encodePacked(_configData, _immutables, _customConfigData));\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            _pairAddress := create2(0, add(bytecode, 32), mload(bytecode), salt)\n        }\n        if (_pairAddress == address(0)) revert Create2Failed();\n\n        deployedPairsArray.push(_pairAddress);\n\n        // Set additional values for SturdyPair\n        ISturdyPair _sturdyPair = ISturdyPair(_pairAddress);\n        address[] memory _defaultSwappers = defaultSwappers;\n        for (uint256 i = 0; i < _defaultSwappers.length; i++) {\n            _sturdyPair.setSwapper(_defaultSwappers[i], true);\n        }\n\n        return _pairAddress;\n    }\n\n    // ============================================================================================\n    // Functions: External Deploy Methods\n    // ============================================================================================\n\n    /// @notice The ```deploy``` function allows the deployment of a SturdyPair with default values\n    /// @param _configData abi.encode(address _asset, address _collateral, address _oracle, uint32 _maxOracleDeviation, address _rateContract, uint64 _fullUtilizationRate, uint256 _maxLTV, uint256 _cleanLiquidationFee, uint256 _dirtyLiquidationFee, uint256 _protocolLiquidationFee)\n    /// @return _pairAddress The address to which the Pair was deployed\n    function deploy(bytes memory _configData) external returns (address _pairAddress) {\n        if (!ISturdyWhitelist(sturdyWhitelistAddress).sturdyDeployerWhitelist(msg.sender)) {\n            revert WhitelistedDeployersOnly();\n        }\n\n        (address _asset, address _collateral, , , , , , , ) = abi.decode(\n            _configData,\n            (address, address, address, uint32, address, uint64, uint256, uint256, uint256)\n        );\n\n        (string memory _name, string memory _symbol) = getNextNameSymbol(_asset, _collateral);\n\n        bytes memory _immutables = abi.encode(circuitBreakerAddress, comptrollerAddress, timelockAddress);\n        bytes memory _customConfigData = abi.encode(_name, _symbol, IERC20(_asset).safeDecimals());\n\n        _pairAddress = _deploy(_configData, _immutables, _customConfigData);\n\n        ISturdyPairRegistry(sturdyPairRegistryAddress).addPair(_pairAddress);\n\n        emit LogDeploy(_pairAddress, _asset, _collateral, _name, _configData, _immutables, _customConfigData);\n    }\n\n    // ============================================================================================\n    // Functions: Admin\n    // ============================================================================================\n\n    /// @notice The ```globalPause``` function calls the pause() function on a given set of pair addresses\n    /// @dev Ignores reverts when calling pause()\n    /// @param _addresses Addresses to attempt to pause()\n    /// @return _updatedAddresses Addresses for which pause() was successful\n    function globalPause(address[] memory _addresses) external returns (address[] memory _updatedAddresses) {\n        if (msg.sender != circuitBreakerAddress) revert CircuitBreakerOnly();\n\n        address _pairAddress;\n        uint256 _lengthOfArray = _addresses.length;\n        _updatedAddresses = new address[](_lengthOfArray);\n        for (uint256 i = 0; i < _lengthOfArray; ) {\n            _pairAddress = _addresses[i];\n            try ISturdyPair(_pairAddress).pause() {\n                _updatedAddresses[i] = _addresses[i];\n            } catch {}\n            unchecked {\n                i = i + 1;\n            }\n        }\n    }\n\n    // ============================================================================================\n    // Errors\n    // ============================================================================================\n\n    error CircuitBreakerOnly();\n    error WhitelistedDeployersOnly();\n    error Create2Failed();\n}\n"
      },
      "contracts/src/SturdyPairRegistry.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ====================== SturdyPairRegistry ========================\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\n\ncontract SturdyPairRegistry is Ownable2Step {\n    /// @notice addresses of deployers allowed to add to the registry\n    mapping(address => bool) public deployers;\n\n    /// @notice List of the addresses of all deployed Pairs\n    address[] public deployedPairsArray;\n\n    /// @notice name => deployed address\n    mapping(string => address) public deployedPairsByName;\n\n    constructor(address _ownerAddress, address[] memory _initialDeployers) Ownable2Step() {\n        for (uint256 i = 0; i < _initialDeployers.length; i++) {\n            deployers[_initialDeployers[i]] = true;\n        }\n        _transferOwnership(_ownerAddress);\n    }\n\n    // ============================================================================================\n    // Functions: View Functions\n    // ============================================================================================\n\n    /// @notice The ```deployedPairsLength``` function returns the length of the deployedPairsArray\n    /// @return length of array\n    function deployedPairsLength() external view returns (uint256) {\n        return deployedPairsArray.length;\n    }\n\n    /// @notice The ```getAllPairAddresses``` function returns an array of all deployed pairs\n    /// @return _deployedPairsArray The array of pairs deployed\n    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray) {\n        _deployedPairsArray = deployedPairsArray;\n    }\n\n    // ============================================================================================\n    // Functions: Setters\n    // ============================================================================================\n\n    /// @notice The ```SetDeployer``` event is called when a deployer is added or removed from the whitelist\n    /// @param deployer The address to be set\n    /// @param _bool The value to set (allow or disallow)\n    event SetDeployer(address deployer, bool _bool);\n\n    /// @notice The ```setDeployers``` function sets the deployers whitelist\n    /// @param _deployers The deployers to set\n    /// @param _bool The boolean to set\n    function setDeployers(address[] memory _deployers, bool _bool) external onlyOwner {\n        for (uint256 i = 0; i < _deployers.length; i++) {\n            deployers[_deployers[i]] = _bool;\n            emit SetDeployer(_deployers[i], _bool);\n        }\n    }\n\n    // ============================================================================================\n    // Functions: External Methods\n    // ============================================================================================\n\n    /// @notice The ```AddPair``` event is emitted when a new pair is added to the registry\n    /// @param pairAddress The address of the pair\n    event AddPair(address pairAddress);\n\n    /// @notice The ```addPair``` function adds a pair to the registry and ensures a unique name\n    /// @param _pairAddress The address of the pair\n    function addPair(address _pairAddress) external {\n        // Ensure caller is on the whitelist\n        if (!deployers[msg.sender]) revert AddressIsNotDeployer();\n\n        // Add pair to the global list\n        deployedPairsArray.push(_pairAddress);\n\n        // Pull name, ensure uniqueness and add to the name mapping\n        string memory _name = IERC20Metadata(_pairAddress).name();\n        if (deployedPairsByName[_name] != address(0)) revert NameMustBeUnique();\n        deployedPairsByName[_name] = _pairAddress;\n\n        emit AddPair(_pairAddress);\n    }\n\n    // ============================================================================================\n    // Errors\n    // ============================================================================================\n\n    error AddressIsNotDeployer();\n    error NameMustBeUnique();\n}\n"
      },
      "contracts/src/SturdyWhitelist.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ======================= SturdyWhitelist ==========================\n\nimport { Ownable2Step } from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\n\ncontract SturdyWhitelist is Ownable2Step {\n    /// @notice Sturdy Deployer Whitelist mapping.\n    mapping(address => bool) public sturdyDeployerWhitelist;\n\n    constructor() Ownable2Step() {}\n\n    /// @notice The ```SetSturdyDeployerWhitelist``` event fires whenever a status is set for a given address.\n    /// @param _address address being set.\n    /// @param _bool approval being set.\n    event SetSturdyDeployerWhitelist(address indexed _address, bool _bool);\n\n    /// @notice The ```setSturdyDeployerWhitelist``` function sets a given address to true/false for use as a custom deployer.\n    /// @param _addresses addresses to set status for.\n    /// @param _bool status of approval.\n    function setSturdyDeployerWhitelist(address[] calldata _addresses, bool _bool) external onlyOwner {\n        for (uint256 i = 0; i < _addresses.length; i++) {\n            sturdyDeployerWhitelist[_addresses[i]] = _bool;\n            emit SetSturdyDeployerWhitelist(_addresses[i], _bool);\n        }\n    }\n}\n"
      },
      "contracts/src/swappers/BalancerswapAdapter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IBalancerVault} from \"../interfaces/Balancer/IBalancerVault.sol\";\n\nlibrary BalancerswapAdapter {\n  using SafeERC20 for IERC20;\n\n  struct Path {\n    address[] tokens;\n    bytes32[] poolIds;\n  }\n\n  error SW_PATH_LENGTH_INVALID();\n  error SW_PATH_TOKEN_INVALID();\n  error SW_MISMATCH_RETURNED_AMOUNT();\n\n  address private constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;\n\n  function swapExactTokensForTokens(\n    address assetToSwapFrom,\n    address assetToSwapTo,\n    uint256 amountToSwap,\n    Path calldata path,\n    uint256 minAmountOut\n  ) external returns (uint256) {\n    // Check path is valid\n    uint256 length = path.tokens.length;\n    if (length <= 1 || length - 1 != path.poolIds.length) revert SW_PATH_LENGTH_INVALID();\n    if (path.tokens[0] != assetToSwapFrom || path.tokens[length - 1] != assetToSwapTo) revert SW_PATH_TOKEN_INVALID();\n\n    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.\n    IERC20(assetToSwapFrom).safeApprove(address(BALANCER_VAULT), 0);\n    if (IERC20(assetToSwapFrom).allowance(address(this), address(BALANCER_VAULT)) == 0)\n      IERC20(assetToSwapFrom).safeApprove(address(BALANCER_VAULT), amountToSwap);\n\n    IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](length - 1);\n    int256[] memory limits = new int256[](length);\n    for (uint256 i; i < length - 1; ++i) {\n      swaps[i] = IBalancerVault.BatchSwapStep({\n        poolId: path.poolIds[i],\n        assetInIndex: i,\n        assetOutIndex: i + 1,\n        amount: 0,\n        userData: \"0\"\n      });\n    }\n    swaps[0].amount = amountToSwap;\n    limits[0] = int256(amountToSwap);\n    unchecked {\n      limits[length - 1] = int256(0 - minAmountOut);\n    }\n\n    IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({\n      sender: address(this),\n      fromInternalBalance: false,\n      recipient: payable(address(this)),\n      toInternalBalance: false\n    });\n\n    int256[] memory receivedAmount = IBalancerVault(BALANCER_VAULT).batchSwap(\n      IBalancerVault.SwapKind.GIVEN_IN,\n      swaps,\n      path.tokens,\n      funds,\n      limits,\n      block.timestamp\n    );\n\n    uint256 receivedPositveAmount;\n    unchecked {\n      receivedPositveAmount = uint256(0 - receivedAmount[length - 1]);\n    }\n\n    if (receivedPositveAmount == 0) revert SW_MISMATCH_RETURNED_AMOUNT();\n    if (IERC20(assetToSwapTo).balanceOf(address(this)) < receivedPositveAmount) revert SW_MISMATCH_RETURNED_AMOUNT();\n\n    return receivedPositveAmount;\n  }\n}\n"
      },
      "contracts/src/swappers/CurveswapAdapter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ICurveAddressProvider} from \"../interfaces/Curve/ICurveAddressProvider.sol\";\nimport {ICurveExchange} from \"../interfaces/Curve/ICurveExchange.sol\";\n\nlibrary CurveswapAdapter {\n  using SafeERC20 for IERC20;\n\n  error SW_MISMATCH_RETURNED_AMOUNT();\n\n  address private constant curveAddressProvider = 0x0000000022D53366457F9d5E68Ec105046FC4383;\n\n  struct Path {\n    address[9] routes;\n    uint256[3][4] swapParams;\n  }\n\n  address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n  function swapExactTokensForTokens(\n    address assetToSwapFrom,\n    address assetToSwapTo,\n    uint256 amountToSwap,\n    Path calldata path,\n    uint256 minAmountOut\n  ) external returns (uint256) {\n    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.\n    address curveExchange = ICurveAddressProvider(curveAddressProvider).get_address(2);\n\n    IERC20(assetToSwapFrom).safeApprove(address(curveExchange), 0);\n    IERC20(assetToSwapFrom).safeApprove(address(curveExchange), amountToSwap);\n\n    address[4] memory pools;\n    uint256 receivedAmount = ICurveExchange(curveExchange).exchange_multiple(\n      path.routes,\n      path.swapParams,\n      amountToSwap,\n      minAmountOut,\n      pools,\n      address(this)\n    );\n\n    if (receivedAmount == 0) revert SW_MISMATCH_RETURNED_AMOUNT();\n    uint256 balanceOfAsset;\n    if (assetToSwapTo == ETH) {\n      balanceOfAsset = address(this).balance;\n    } else {\n      balanceOfAsset = IERC20(assetToSwapTo).balanceOf(address(this));\n    }\n    if (balanceOfAsset < receivedAmount - 2) revert SW_MISMATCH_RETURNED_AMOUNT();\n    return balanceOfAsset;\n  }\n}\n"
      },
      "contracts/src/swappers/Mode/SupswapAdapter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IV3SwapRouter} from \"../../interfaces/Mode/Supswap/IV3SwapRouter.sol\";\n\nlibrary SupswapAdapter {\n  using SafeERC20 for IERC20;\n\n  error SW_PATH_LENGTH_INVALID();\n  error SW_PATH_TOKEN_INVALID();\n  error SW_MISMATCH_RETURNED_AMOUNT();\n\n  address private constant SUPSWAP_ROUTER = 0x016e131C05fb007b5ab286A6D614A5dab99BD415;\n\n  struct Path {\n    address[] tokens;\n    uint256[] fees;\n  }\n\n  function swapExactTokensForTokens(\n    address assetToSwapFrom,\n    address assetToSwapTo,\n    uint256 amountToSwap,\n    Path calldata path,\n    uint256 minAmountOut\n  ) external returns (uint256) {\n    // Check path is valid\n    uint256 length = path.tokens.length;\n    if (length <= 1 || length - 1 != path.fees.length) revert SW_PATH_LENGTH_INVALID();\n    if (path.tokens[0] != assetToSwapFrom || path.tokens[length - 1] != assetToSwapTo) revert SW_PATH_TOKEN_INVALID();\n\n    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.\n    IERC20(assetToSwapFrom).safeApprove(address(SUPSWAP_ROUTER), 0);\n    IERC20(assetToSwapFrom).safeApprove(address(SUPSWAP_ROUTER), amountToSwap);\n\n    uint256 receivedAmount;\n    if (length > 2) {\n      bytes memory _path;\n\n      for (uint256 i; i < length - 1; ++i) {\n        _path = abi.encodePacked(_path, path.tokens[i], uint24(path.fees[i]));\n      }\n      _path = abi.encodePacked(_path, assetToSwapTo);\n\n      IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter.ExactInputParams({\n        path: _path,\n        recipient: address(this),\n        amountIn: amountToSwap,\n        amountOutMinimum: minAmountOut\n      });\n\n      // Executes the swap.\n      receivedAmount = IV3SwapRouter(SUPSWAP_ROUTER).exactInput(params);\n    } else {\n      IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams({\n        tokenIn: assetToSwapFrom,\n        tokenOut: assetToSwapTo,\n        fee: uint24(path.fees[0]),\n        recipient: address(this),\n        amountIn: amountToSwap,\n        amountOutMinimum: minAmountOut,\n        sqrtPriceLimitX96: 0\n      });\n\n      // Executes the swap.\n      receivedAmount = IV3SwapRouter(SUPSWAP_ROUTER).exactInputSingle(params);\n    }\n\n    if (receivedAmount == 0) revert SW_MISMATCH_RETURNED_AMOUNT();\n    if (IERC20(assetToSwapTo).balanceOf(address(this)) < receivedAmount) revert SW_MISMATCH_RETURNED_AMOUNT();\n\n    return receivedAmount;\n  }\n}\n"
      },
      "contracts/src/swappers/UniswapAdapter.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity ^0.8.21;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {ISwapRouter} from \"../interfaces/Uniswap/V3/ISwapRouter.sol\";\n\nlibrary UniswapAdapter {\n  using SafeERC20 for IERC20;\n\n  error SW_PATH_LENGTH_INVALID();\n  error SW_PATH_TOKEN_INVALID();\n  error SW_MISMATCH_RETURNED_AMOUNT();\n\n  address private constant UNISWAP_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;\n\n  struct Path {\n    address[] tokens;\n    uint256[] fees;\n  }\n\n  function swapExactTokensForTokens(\n    address assetToSwapFrom,\n    address assetToSwapTo,\n    uint256 amountToSwap,\n    Path calldata path,\n    uint256 minAmountOut\n  ) external returns (uint256) {\n    // Check path is valid\n    uint256 length = path.tokens.length;\n    if (length <= 1 || length - 1 != path.fees.length) revert SW_PATH_LENGTH_INVALID();\n    if (path.tokens[0] != assetToSwapFrom || path.tokens[length - 1] != assetToSwapTo) revert SW_PATH_TOKEN_INVALID();\n\n    // Approves the transfer for the swap. Approves for 0 first to comply with tokens that implement the anti frontrunning approval fix.\n    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), 0);\n    IERC20(assetToSwapFrom).safeApprove(address(UNISWAP_ROUTER), amountToSwap);\n\n    uint256 receivedAmount;\n    if (length > 2) {\n      bytes memory _path;\n\n      for (uint256 i; i < length - 1; ++i) {\n        _path = abi.encodePacked(_path, path.tokens[i], uint24(path.fees[i]));\n      }\n      _path = abi.encodePacked(_path, assetToSwapTo);\n\n      ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({\n        path: _path,\n        recipient: address(this),\n        deadline: block.timestamp,\n        amountIn: amountToSwap,\n        amountOutMinimum: minAmountOut\n      });\n\n      // Executes the swap.\n      receivedAmount = ISwapRouter(UNISWAP_ROUTER).exactInput(params);\n    } else {\n      ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({\n        tokenIn: assetToSwapFrom,\n        tokenOut: assetToSwapTo,\n        fee: uint24(path.fees[0]),\n        recipient: address(this),\n        deadline: block.timestamp,\n        amountIn: amountToSwap,\n        amountOutMinimum: minAmountOut,\n        sqrtPriceLimitX96: 0\n      });\n\n      // Executes the swap.\n      receivedAmount = ISwapRouter(UNISWAP_ROUTER).exactInputSingle(params);\n    }\n\n    if (receivedAmount == 0) revert SW_MISMATCH_RETURNED_AMOUNT();\n    if (IERC20(assetToSwapTo).balanceOf(address(this)) < receivedAmount) revert SW_MISMATCH_RETURNED_AMOUNT();\n\n    return receivedAmount;\n  }\n}\n"
      },
      "contracts/src/Timelock2Step.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ========================== Timelock2Step ===========================\n\n/// @title Timelock2Step\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @dev Inspired by the OpenZeppelin's Ownable2Step contract\n/// @notice  An abstract contract which contains 2-step transfer and renounce logic for a timelock address\nabstract contract Timelock2Step {\n    /// @notice The pending timelock address\n    address public pendingTimelockAddress;\n\n    /// @notice The current timelock address\n    address public timelockAddress;\n\n    constructor() {\n        timelockAddress = msg.sender;\n    }\n\n    /// @notice Emitted when timelock is transferred\n    error OnlyTimelock();\n\n    /// @notice Emitted when pending timelock is transferred\n    error OnlyPendingTimelock();\n\n    /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);\n\n    /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);\n\n    /// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address\n    /// @return Whether or not msg.sender is current timelock address\n    function _isSenderTimelock() internal view returns (bool) {\n        return msg.sender == timelockAddress;\n    }\n\n    /// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address\n    function _requireTimelock() internal view {\n        if (msg.sender != timelockAddress) revert OnlyTimelock();\n    }\n\n    /// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address\n    /// @return Whether or not msg.sender is pending timelock address\n    function _isSenderPendingTimelock() internal view returns (bool) {\n        return msg.sender == pendingTimelockAddress;\n    }\n\n    /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address\n    function _requirePendingTimelock() internal view {\n        if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();\n    }\n\n    /// @notice The ```_transferTimelock``` function initiates the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function _transferTimelock(address _newTimelock) internal {\n        pendingTimelockAddress = _newTimelock;\n        emit TimelockTransferStarted(timelockAddress, _newTimelock);\n    }\n\n    /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    function _acceptTransferTimelock() internal {\n        pendingTimelockAddress = address(0);\n        _setTimelock(msg.sender);\n    }\n\n    /// @notice The ```_setTimelock``` function sets the timelock address\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the new timelock\n    function _setTimelock(address _newTimelock) internal {\n        emit TimelockTransferred(timelockAddress, _newTimelock);\n        timelockAddress = _newTimelock;\n    }\n\n    /// @notice The ```transferTimelock``` function initiates the timelock transfer\n    /// @dev Must be called by the current timelock\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function transferTimelock(address _newTimelock) external virtual {\n        _requireTimelock();\n        _transferTimelock(_newTimelock);\n    }\n\n    /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev Must be called by the pending timelock\n    function acceptTransferTimelock() external virtual {\n        _requirePendingTimelock();\n        _acceptTransferTimelock();\n    }\n\n    /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock\n    /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process\n    function renounceTimelock() external virtual {\n        _requireTimelock();\n        _requirePendingTimelock();\n        _transferTimelock(address(0));\n        _setTimelock(address(0));\n    }\n}\n"
      },
      "contracts/src/VariableInterestRate.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.21;\n\n// ====================== VariableInterestRate ========================\n\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\nimport { IRateCalculatorV2 } from \"./interfaces/IRateCalculatorV2.sol\";\n\n/// @title A formula for calculating interest rates as a function of utilization and time\n/// @author Drake Evans github.com/drakeevans\n/// @notice A Contract for calculating interest rates as a function of utilization and time\ncontract VariableInterestRate is IRateCalculatorV2 {\n    using Strings for uint256;\n\n    /// @notice The name suffix for the interest rate calculator\n    string public suffix;\n\n    // Utilization Settings\n    /// @notice The minimum utilization wherein no adjustment to full utilization and vertex rates occurs\n    uint256 public immutable MIN_TARGET_UTIL;\n    /// @notice The maximum utilization wherein no adjustment to full utilization and vertex rates occurs\n    uint256 public immutable MAX_TARGET_UTIL;\n    /// @notice The utilization at which the slope increases\n    uint256 public immutable VERTEX_UTILIZATION;\n    /// @notice precision of utilization calculations\n    uint256 public constant UTIL_PREC = 1e5; // 5 decimals\n\n    // Interest Rate Settings (all rates are per second), 365.24 days per year\n    /// @notice The minimum interest rate (per second) when utilization is 100%\n    uint256 public immutable MIN_FULL_UTIL_RATE; // 18 decimals\n    /// @notice The maximum interest rate (per second) when utilization is 100%\n    uint256 public immutable MAX_FULL_UTIL_RATE; // 18 decimals\n    /// @notice The interest rate (per second) when utilization is 0%\n    uint256 public immutable ZERO_UTIL_RATE; // 18 decimals\n    /// @notice The interest rate half life in seconds, determines rate of adjustments to rate curve\n    uint256 public immutable RATE_HALF_LIFE; // 1 decimals\n    /// @notice The percent of the delta between max and min\n    uint256 public immutable VERTEX_RATE_PERCENT; // 18 decimals\n    /// @notice The precision of interest rate calculations\n    uint256 public constant RATE_PREC = 1e18; // 18 decimals\n\n    /// @notice The ```constructor``` function\n    /// @param _suffix The suffix of the contract name\n    /// @param _vertexUtilization The utilization at which the slope increases\n    /// @param _vertexRatePercentOfDelta The percent of the delta between max and min, defines vertex rate\n    /// @param _minUtil The minimum utilization wherein no adjustment to full utilization and vertex rates occurs\n    /// @param _maxUtil The maximum utilization wherein no adjustment to full utilization and vertex rates occurs\n    /// @param _zeroUtilizationRate The interest rate (per second) when utilization is 0%\n    /// @param _minFullUtilizationRate The minimum interest rate at 100% utilization\n    /// @param _maxFullUtilizationRate The maximum interest rate at 100% utilization\n    /// @param _rateHalfLife The half life parameter for interest rate adjustments\n    constructor(\n        string memory _suffix,\n        uint256 _vertexUtilization,\n        uint256 _vertexRatePercentOfDelta,\n        uint256 _minUtil,\n        uint256 _maxUtil,\n        uint256 _zeroUtilizationRate,\n        uint256 _minFullUtilizationRate,\n        uint256 _maxFullUtilizationRate,\n        uint256 _rateHalfLife\n    ) {\n        suffix = _suffix;\n        MIN_TARGET_UTIL = _minUtil;\n        MAX_TARGET_UTIL = _maxUtil;\n        VERTEX_UTILIZATION = _vertexUtilization;\n        ZERO_UTIL_RATE = _zeroUtilizationRate;\n        MIN_FULL_UTIL_RATE = _minFullUtilizationRate;\n        MAX_FULL_UTIL_RATE = _maxFullUtilizationRate;\n        RATE_HALF_LIFE = _rateHalfLife;\n        VERTEX_RATE_PERCENT = _vertexRatePercentOfDelta;\n    }\n\n    /// @notice The ```name``` function returns the name of the rate contract\n    /// @return memory name of contract\n    function name() external view returns (string memory) {\n        return string(abi.encodePacked(\"Variable Rate V2 \", suffix));\n    }\n\n    /// @notice The ```version``` function returns the semantic version of the rate contract\n    /// @dev Follows semantic versioning\n    /// @return _major Major version\n    /// @return _minor Minor version\n    /// @return _patch Patch version\n    function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {\n        _major = 2;\n        _minor = 0;\n        _patch = 0;\n    }\n\n    /// @notice The ```getFullUtilizationInterest``` function calculate the new maximum interest rate, i.e. rate when utilization is 100%\n    /// @dev Given in interest per second\n    /// @param _deltaTime The elapsed time since last update given in seconds\n    /// @param _utilization The utilization %, given with 5 decimals of precision\n    /// @param _fullUtilizationInterest The interest value when utilization is 100%, given with 18 decimals of precision\n    /// @return _newFullUtilizationInterest The new maximum interest rate\n    function getFullUtilizationInterest(\n        uint256 _deltaTime,\n        uint256 _utilization,\n        uint64 _fullUtilizationInterest\n    ) internal view returns (uint64 _newFullUtilizationInterest) {\n        if (_utilization < MIN_TARGET_UTIL) {\n            // 18 decimals\n            uint256 _deltaUtilization = ((MIN_TARGET_UTIL - _utilization) * 1e18) / MIN_TARGET_UTIL;\n            // 36 decimals\n            uint256 _decayGrowth = (RATE_HALF_LIFE * 1e36) + (_deltaUtilization * _deltaUtilization * _deltaTime);\n            // 18 decimals\n            _newFullUtilizationInterest = uint64((_fullUtilizationInterest * (RATE_HALF_LIFE * 1e36)) / _decayGrowth);\n        } else if (_utilization > MAX_TARGET_UTIL) {\n            // 18 decimals\n            uint256 _deltaUtilization = ((_utilization - MAX_TARGET_UTIL) * 1e18) / (UTIL_PREC - MAX_TARGET_UTIL);\n            // 36 decimals\n            uint256 _decayGrowth = (RATE_HALF_LIFE * 1e36) + (_deltaUtilization * _deltaUtilization * _deltaTime);\n            // 18 decimals\n            _newFullUtilizationInterest = uint64((_fullUtilizationInterest * _decayGrowth) / (RATE_HALF_LIFE * 1e36));\n        } else {\n            _newFullUtilizationInterest = _fullUtilizationInterest;\n        }\n        if (_newFullUtilizationInterest > MAX_FULL_UTIL_RATE) {\n            _newFullUtilizationInterest = uint64(MAX_FULL_UTIL_RATE);\n        } else if (_newFullUtilizationInterest < MIN_FULL_UTIL_RATE) {\n            _newFullUtilizationInterest = uint64(MIN_FULL_UTIL_RATE);\n        }\n    }\n\n    /// @notice The ```getNewRate``` function calculates interest rates using two linear functions f(utilization)\n    /// @param _deltaTime The elapsed time since last update, given in seconds\n    /// @param _utilization The utilization %, given with 5 decimals of precision\n    /// @param _oldFullUtilizationInterest The interest value when utilization is 100%, given with 18 decimals of precision\n    /// @return _newRatePerSec The new interest rate, 18 decimals of precision\n    /// @return _newFullUtilizationInterest The new max interest rate, 18 decimals of precision\n    function getNewRate(\n        uint256 _deltaTime,\n        uint256 _utilization,\n        uint64 _oldFullUtilizationInterest\n    ) external view returns (uint64 _newRatePerSec, uint64 _newFullUtilizationInterest) {\n        // _newFullUtilizationInterest = getFullUtilizationInterest(_deltaTime, _utilization, _oldFullUtilizationInterest);\n        _newFullUtilizationInterest = uint64(MAX_FULL_UTIL_RATE);\n\n        // _vertexInterest is calculated as the percentage of the delta between min and max interest\n        uint256 _vertexInterest = (((_newFullUtilizationInterest - ZERO_UTIL_RATE) * VERTEX_RATE_PERCENT) / RATE_PREC) +\n            ZERO_UTIL_RATE;\n        if (_utilization < VERTEX_UTILIZATION) {\n            // For readability, the following formula is equivalent to:\n            // uint256 _slope = ((_vertexInterest - ZERO_UTIL_RATE) * UTIL_PREC) / VERTEX_UTILIZATION;\n            // _newRatePerSec = uint64(ZERO_UTIL_RATE + ((_utilization * _slope) / UTIL_PREC));\n\n            // 18 decimals\n            _newRatePerSec = uint64(\n                ZERO_UTIL_RATE + (_utilization * (_vertexInterest - ZERO_UTIL_RATE)) / VERTEX_UTILIZATION\n            );\n        } else {\n            // For readability, the following formula is equivalent to:\n            // uint256 _slope = (((_newFullUtilizationInterest - _vertexInterest) * UTIL_PREC) / (UTIL_PREC - VERTEX_UTILIZATION));\n            // _newRatePerSec = uint64(_vertexInterest + (((_utilization - VERTEX_UTILIZATION) * _slope) / UTIL_PREC));\n\n            // 18 decimals\n            _newRatePerSec = uint64(\n                _vertexInterest +\n                    ((_utilization - VERTEX_UTILIZATION) * (_newFullUtilizationInterest - _vertexInterest)) /\n                    (UTIL_PREC - VERTEX_UTILIZATION)\n            );\n        }\n    }\n}\n"
      },
      "solidity-bytes-utils/contracts/BytesLib.sol": {
        "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá <goncalo.sa@consensys.net>\n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\n\nlibrary BytesLib {\n    function concat(\n        bytes memory _preBytes,\n        bytes memory _postBytes\n    )\n        internal\n        pure\n        returns (bytes memory)\n    {\n        bytes memory tempBytes;\n\n        assembly {\n            // Get a location of some free memory and store it in tempBytes as\n            // Solidity does for memory variables.\n            tempBytes := mload(0x40)\n\n            // Store the length of the first bytes array at the beginning of\n            // the memory for tempBytes.\n            let length := mload(_preBytes)\n            mstore(tempBytes, length)\n\n            // Maintain a memory counter for the current write location in the\n            // temp bytes array by adding the 32 bytes for the array length to\n            // the starting location.\n            let mc := add(tempBytes, 0x20)\n            // Stop copying when the memory counter reaches the length of the\n            // first bytes array.\n            let end := add(mc, length)\n\n            for {\n                // Initialize a copy counter to the start of the _preBytes data,\n                // 32 bytes into its memory.\n                let cc := add(_preBytes, 0x20)\n            } lt(mc, end) {\n                // Increase both counters by 32 bytes each iteration.\n                mc := add(mc, 0x20)\n                cc := add(cc, 0x20)\n            } {\n                // Write the _preBytes data into the tempBytes memory 32 bytes\n                // at a time.\n                mstore(mc, mload(cc))\n            }\n\n            // Add the length of _postBytes to the current length of tempBytes\n            // and store it as the new length in the first 32 bytes of the\n            // tempBytes memory.\n            length := mload(_postBytes)\n            mstore(tempBytes, add(length, mload(tempBytes)))\n\n            // Move the memory counter back from a multiple of 0x20 to the\n            // actual end of the _preBytes data.\n            mc := end\n            // Stop copying when the memory counter reaches the new combined\n            // length of the arrays.\n            end := add(mc, length)\n\n            for {\n                let cc := add(_postBytes, 0x20)\n            } lt(mc, end) {\n                mc := add(mc, 0x20)\n                cc := add(cc, 0x20)\n            } {\n                mstore(mc, mload(cc))\n            }\n\n            // Update the free-memory pointer by padding our last write location\n            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n            // next 32 byte block, then round down to the nearest multiple of\n            // 32. If the sum of the length of the two arrays is zero then add\n            // one before rounding down to leave a blank 32 bytes (the length block with 0).\n            mstore(0x40, and(\n              add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n              not(31) // Round down to the nearest 32 bytes.\n            ))\n        }\n\n        return tempBytes;\n    }\n\n    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n        assembly {\n            // Read the first 32 bytes of _preBytes storage, which is the length\n            // of the array. (We don't need to use the offset into the slot\n            // because arrays use the entire slot.)\n            let fslot := sload(_preBytes.slot)\n            // Arrays of 31 bytes or less have an even value in their slot,\n            // while longer arrays have an odd value. The actual length is\n            // the slot divided by two for odd values, and the lowest order\n            // byte divided by two for even values.\n            // If the slot is even, bitwise and the slot with 255 and divide by\n            // two to get the length. If the slot is odd, bitwise and the slot\n            // with -1 and divide by two.\n            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n            let mlength := mload(_postBytes)\n            let newlength := add(slength, mlength)\n            // slength can contain both the length and contents of the array\n            // if length < 32 bytes so let's prepare for that\n            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n            switch add(lt(slength, 32), lt(newlength, 32))\n            case 2 {\n                // Since the new array still fits in the slot, we just need to\n                // update the contents of the slot.\n                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n                sstore(\n                    _preBytes.slot,\n                    // all the modifications to the slot are inside this\n                    // next block\n                    add(\n                        // we can just add to the slot contents because the\n                        // bytes we want to change are the LSBs\n                        fslot,\n                        add(\n                            mul(\n                                div(\n                                    // load the bytes from memory\n                                    mload(add(_postBytes, 0x20)),\n                                    // zero all bytes to the right\n                                    exp(0x100, sub(32, mlength))\n                                ),\n                                // and now shift left the number of bytes to\n                                // leave space for the length in the slot\n                                exp(0x100, sub(32, newlength))\n                            ),\n                            // increase length by the double of the memory\n                            // bytes length\n                            mul(mlength, 2)\n                        )\n                    )\n                )\n            }\n            case 1 {\n                // The stored value fits in the slot, but the combined value\n                // will exceed it.\n                // get the keccak hash to get the contents of the array\n                mstore(0x0, _preBytes.slot)\n                let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n                // save new length\n                sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n                // The contents of the _postBytes array start 32 bytes into\n                // the structure. Our first read should obtain the `submod`\n                // bytes that can fit into the unused space in the last word\n                // of the stored array. To get this, we read 32 bytes starting\n                // from `submod`, so the data we read overlaps with the array\n                // contents by `submod` bytes. Masking the lowest-order\n                // `submod` bytes allows us to add that value directly to the\n                // stored value.\n\n                let submod := sub(32, slength)\n                let mc := add(_postBytes, submod)\n                let end := add(_postBytes, mlength)\n                let mask := sub(exp(0x100, submod), 1)\n\n                sstore(\n                    sc,\n                    add(\n                        and(\n                            fslot,\n                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n                        ),\n                        and(mload(mc), mask)\n                    )\n                )\n\n                for {\n                    mc := add(mc, 0x20)\n                    sc := add(sc, 1)\n                } lt(mc, end) {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } {\n                    sstore(sc, mload(mc))\n                }\n\n                mask := exp(0x100, sub(mc, end))\n\n                sstore(sc, mul(div(mload(mc), mask), mask))\n            }\n            default {\n                // get the keccak hash to get the contents of the array\n                mstore(0x0, _preBytes.slot)\n                // Start copying to the last used word of the stored array.\n                let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n                // save new length\n                sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n                // Copy over the first `submod` bytes of the new data as in\n                // case 1 above.\n                let slengthmod := mod(slength, 32)\n                let mlengthmod := mod(mlength, 32)\n                let submod := sub(32, slengthmod)\n                let mc := add(_postBytes, submod)\n                let end := add(_postBytes, mlength)\n                let mask := sub(exp(0x100, submod), 1)\n\n                sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n                for {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } lt(mc, end) {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } {\n                    sstore(sc, mload(mc))\n                }\n\n                mask := exp(0x100, sub(mc, end))\n\n                sstore(sc, mul(div(mload(mc), mask), mask))\n            }\n        }\n    }\n\n    function slice(\n        bytes memory _bytes,\n        uint256 _start,\n        uint256 _length\n    )\n        internal\n        pure\n        returns (bytes memory)\n    {\n        require(_length + 31 >= _length, \"slice_overflow\");\n        require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n        bytes memory tempBytes;\n\n        assembly {\n            switch iszero(_length)\n            case 0 {\n                // Get a location of some free memory and store it in tempBytes as\n                // Solidity does for memory variables.\n                tempBytes := mload(0x40)\n\n                // The first word of the slice result is potentially a partial\n                // word read from the original array. To read it, we calculate\n                // the length of that partial word and start copying that many\n                // bytes into the array. The first word we copy will start with\n                // data we don't care about, but the last `lengthmod` bytes will\n                // land at the beginning of the contents of the new array. When\n                // we're done copying, we overwrite the full first word with\n                // the actual length of the slice.\n                let lengthmod := and(_length, 31)\n\n                // The multiplication in the next line is necessary\n                // because when slicing multiples of 32 bytes (lengthmod == 0)\n                // the following copy loop was copying the origin's length\n                // and then ending prematurely not copying everything it should.\n                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n                let end := add(mc, _length)\n\n                for {\n                    // The multiplication in the next line has the same exact purpose\n                    // as the one above.\n                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n                } lt(mc, end) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } {\n                    mstore(mc, mload(cc))\n                }\n\n                mstore(tempBytes, _length)\n\n                //update free-memory pointer\n                //allocating the array padded to 32 bytes like the compiler does now\n                mstore(0x40, and(add(mc, 31), not(31)))\n            }\n            //if we want a zero-length slice let's just return a zero-length array\n            default {\n                tempBytes := mload(0x40)\n                //zero out the 32 bytes slice we are about to return\n                //we need to do it because Solidity does not garbage collect\n                mstore(tempBytes, 0)\n\n                mstore(0x40, add(tempBytes, 0x20))\n            }\n        }\n\n        return tempBytes;\n    }\n\n    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n        require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n        address tempAddress;\n\n        assembly {\n            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n        }\n\n        return tempAddress;\n    }\n\n    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n        require(_bytes.length >= _start + 1 , \"toUint8_outOfBounds\");\n        uint8 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x1), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n        require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n        uint16 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x2), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n        require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n        uint32 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x4), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n        require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n        uint64 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x8), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n        require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n        uint96 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0xc), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n        require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n        uint128 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x10), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n        require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n        uint256 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n        require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n        bytes32 tempBytes32;\n\n        assembly {\n            tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempBytes32;\n    }\n\n    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n        bool success = true;\n\n        assembly {\n            let length := mload(_preBytes)\n\n            // if lengths don't match the arrays are not equal\n            switch eq(length, mload(_postBytes))\n            case 1 {\n                // cb is a circuit breaker in the for loop since there's\n                //  no said feature for inline assembly loops\n                // cb = 1 - don't breaker\n                // cb = 0 - break\n                let cb := 1\n\n                let mc := add(_preBytes, 0x20)\n                let end := add(mc, length)\n\n                for {\n                    let cc := add(_postBytes, 0x20)\n                // the next line is the loop condition:\n                // while(uint256(mc < end) + cb == 2)\n                } eq(add(lt(mc, end), cb), 2) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } {\n                    // if any of these checks fails then arrays are not equal\n                    if iszero(eq(mload(mc), mload(cc))) {\n                        // unsuccess:\n                        success := 0\n                        cb := 0\n                    }\n                }\n            }\n            default {\n                // unsuccess:\n                success := 0\n            }\n        }\n\n        return success;\n    }\n\n    function equalStorage(\n        bytes storage _preBytes,\n        bytes memory _postBytes\n    )\n        internal\n        view\n        returns (bool)\n    {\n        bool success = true;\n\n        assembly {\n            // we know _preBytes_offset is 0\n            let fslot := sload(_preBytes.slot)\n            // Decode the length of the stored array like in concatStorage().\n            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n            let mlength := mload(_postBytes)\n\n            // if lengths don't match the arrays are not equal\n            switch eq(slength, mlength)\n            case 1 {\n                // slength can contain both the length and contents of the array\n                // if length < 32 bytes so let's prepare for that\n                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n                if iszero(iszero(slength)) {\n                    switch lt(slength, 32)\n                    case 1 {\n                        // blank the last byte which is the length\n                        fslot := mul(div(fslot, 0x100), 0x100)\n\n                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n                            // unsuccess:\n                            success := 0\n                        }\n                    }\n                    default {\n                        // cb is a circuit breaker in the for loop since there's\n                        //  no said feature for inline assembly loops\n                        // cb = 1 - don't breaker\n                        // cb = 0 - break\n                        let cb := 1\n\n                        // get the keccak hash to get the contents of the array\n                        mstore(0x0, _preBytes.slot)\n                        let sc := keccak256(0x0, 0x20)\n\n                        let mc := add(_postBytes, 0x20)\n                        let end := add(mc, mlength)\n\n                        // the next line is the loop condition:\n                        // while(uint256(mc < end) + cb == 2)\n                        for {} eq(add(lt(mc, end), cb), 2) {\n                            sc := add(sc, 1)\n                            mc := add(mc, 0x20)\n                        } {\n                            if iszero(eq(sload(sc), mload(mc))) {\n                                // unsuccess:\n                                success := 0\n                                cb := 0\n                            }\n                        }\n                    }\n                }\n            }\n            default {\n                // unsuccess:\n                success := 0\n            }\n        }\n\n        return success;\n    }\n}\n"
      }
    },
    "settings": {
      "viaIR": true,
      "optimizer": {
        "enabled": true,
        "runs": 1660
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {
        "": {
          "__CACHE_BREAKER__": "0x0000000000000031373131323930333438313835"
        }
      }
    }
  }}