creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/periphery/IonLens.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport { IIonPool } from \"../interfaces/IIonPool.sol\";\nimport { IIonLens } from \"../interfaces/IIonLens.sol\";\n\nimport { EnumerableSet } from \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport { StorageSlot } from \"@openzeppelin/contracts/utils/StorageSlot.sol\";\n\nstruct IlkSlot0 {\n    uint104 totalNormalizedDebt; // Total Normalised Debt     [WAD]\n    uint104 rate; // Accumulated Rates         [RAY]\n    uint48 lastRateUpdate; // block.timestamp of last update; overflows in 800_000 years}\n}\n\ncontract IonLens is IIonLens {\n    // --- Data ---\n    struct Ilk {\n        IlkSlot0 slot0;\n        StorageSlot.AddressSlot spot; // Oracle that provides price with safety margin\n        StorageSlot.Uint256Slot debtCeiling; // Debt Ceiling              [RAD]\n        StorageSlot.Uint256Slot dust; // Vault Debt Floor            [RAD]\n    }\n\n    struct Vault {\n        StorageSlot.Uint256Slot collateral; // Locked Collateral  [WAD]\n        StorageSlot.Uint256Slot normalizedDebt; // Normalised Debt    [WAD]\n    }\n\n    /// @custom:storage-location erc7201:ion.storage.IonPool\n    struct IonPoolStorage {\n        Ilk[] ilks;\n        // remove() should never be called, it will mess up the ordering\n        EnumerableSet.AddressSet ilkAddresses;\n        mapping(uint256 ilkIndex => mapping(address user => Vault)) vaults;\n        mapping(uint256 ilkIndex => mapping(address user => StorageSlot.Uint256Slot)) gem; // [WAD]\n        mapping(address unbackedDebtor => StorageSlot.Uint256Slot) unbackedDebt; // [RAD]\n        mapping(address user => mapping(address operator => StorageSlot.Uint256Slot)) isOperator;\n        StorageSlot.Uint256Slot debt; // Total Debt [RAD]\n        StorageSlot.Uint256Slot liquidity; // liquidity in pool [WAD]\n        StorageSlot.Uint256Slot supplyCap; // [WAD]\n        StorageSlot.Uint256Slot totalUnbackedDebt; // Total Unbacked Underlying  [RAD]\n        StorageSlot.AddressSlot interestRateModule;\n        StorageSlot.AddressSlot whitelist;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"ion.storage.IonPool\")) - 1)) & ~uint56(0xff))\n    // solhint-disable-next-line\n    bytes32 private constant IonPoolStorageLocation = 0xceba3d526b4d5afd91d1b752bf1fd37917c20a6daf576bcb41dd1c57c1f67e00;\n\n    bytes4 private constant EXTSLOAD_SELECTOR = 0x1e2eaeaf;\n\n    error SloadFailed();\n    error InvalidFieldSlot();\n\n    constructor() {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n\n        // 4 collaterals should be enough. Must be initialized here to not\n        // trigger an access-out-of-bounds error.\n        $.ilks.push();\n        $.ilks.push();\n        $.ilks.push();\n        $.ilks.push();\n    }\n\n    function _getIonPoolStorage() internal pure returns (IonPoolStorage storage $) {\n        assembly {\n            $.slot := IonPoolStorageLocation\n        }\n    }\n\n    function _toUint256PointerMapping(mapping(bytes32 => uint256) storage inPtr)\n        private\n        pure\n        returns (mapping(address => StorageSlot.Uint256Slot) storage outPtr)\n    {\n        assembly {\n            outPtr.slot := inPtr.slot\n        }\n    }\n\n    function queryPoolSlot(IIonPool pool, uint256 slot) public view returns (uint256 value) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, EXTSLOAD_SELECTOR)\n            mstore(0x04, slot)\n            if iszero(staticcall(gas(), pool, 0x00, 0x24, 0x00, 0x20)) {\n                mstore(0x00, 0x74d9f8d3) // SloadFailed()\n                revert(0x1c, 0x04)\n            }\n            value := mload(0x00)\n        }\n    }\n\n    /**\n     * @return The total amount of collateral in the pool.\n     */\n    function ilkCount(IIonPool pool) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        Ilk[] storage ilks = $.ilks;\n\n        uint256 slot;\n        assembly {\n            // Length of ilks array\n            slot := ilks.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return The index of the collateral with `ilkAddress`.\n     */\n    function getIlkIndex(IIonPool pool, address ilkAddress) external view returns (uint8) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        mapping(address => StorageSlot.Uint256Slot) storage ilksSlot =\n            _toUint256PointerMapping($.ilkAddresses._inner._positions);\n\n        StorageSlot.Uint256Slot storage ptr = ilksSlot[ilkAddress];\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return uint8(value) - 1;\n    }\n\n    /**\n     * @return The total amount of normalized debt for collateral with index\n     * `ilkIndex`.\n     */\n    function totalNormalizedDebt(IIonPool pool, uint8 ilkIndex) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        IlkSlot0 storage ptr = $.ilks[ilkIndex].slot0;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n\n        // Truncate to uint104\n        return uint104(value);\n    }\n\n    /**\n     * @return The `rate` that has been persisted to storage.\n     */\n    function rateUnaccrued(IIonPool pool, uint8 ilkIndex) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        IlkSlot0 storage ptr = $.ilks[ilkIndex].slot0;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        value >>= 104;\n\n        return uint104(value);\n    }\n\n    /**\n     * @return The timestamp of the last rate update for collateral with index\n     * `ilkIndex`.\n     */\n    function lastRateUpdate(IIonPool pool, uint8 ilkIndex) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        IlkSlot0 storage ptr = $.ilks[ilkIndex].slot0;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        value >>= 104 + 104;\n\n        return uint48(value);\n    }\n\n    /**\n     * @return The spot oracle for collateral with index `ilkIndex`.\n     */\n    function spot(IIonPool pool, uint8 ilkIndex) external view returns (address) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.AddressSlot storage ptr = $.ilks[ilkIndex].spot;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n\n        return address(uint160(value));\n    }\n\n    /**\n     * @return The debt ceiling for collateral with index `ilkIndex`.\n     */\n    function debtCeiling(IIonPool pool, uint8 ilkIndex) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.ilks[ilkIndex].debtCeiling;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n\n        return value;\n    }\n\n    /**\n     * @return The dust value for collateral with index `ilkIndex`.\n     */\n    function dust(IIonPool pool, uint8 ilkIndex) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.ilks[ilkIndex].dust;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n\n        return value;\n    }\n\n    /**\n     * @return Amount of `gem` that `user` has for collateral with index `ilkIndex`.\n     */\n    function gem(IIonPool pool, uint8 ilkIndex, address user) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.gem[ilkIndex][user];\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return The amount of unbacked debt `user` has.\n     */\n    function unbackedDebt(IIonPool pool, address unbackedDebtor) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.unbackedDebt[unbackedDebtor];\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return Whether or not `operator` is an `operator` on `user`'s positions.\n     */\n    function isOperator(IIonPool pool, address user, address operator) external view returns (bool) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.isOperator[user][operator];\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value != 0;\n    }\n\n    function debtUnaccrued(IIonPool pool) public view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.debt;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @dev This includes unbacked debt.\n     * @return The total amount of debt.\n     */\n    function debt(IIonPool pool) external view returns (uint256) {\n        (,,, uint256 totalDebtIncrease,) = pool.calculateRewardAndDebtDistribution();\n\n        return debtUnaccrued(pool) + totalDebtIncrease;\n    }\n\n    /**\n     * @return The total amount of ETH liquidity in the pool.\n     */\n    function liquidity(IIonPool pool) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.liquidity;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return The supply cap\n     */\n    function supplyCap(IIonPool pool) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.supplyCap;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return The total amount of unbacked debt.\n     */\n    function totalUnbackedDebt(IIonPool pool) external view returns (uint256) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.Uint256Slot storage ptr = $.totalUnbackedDebt;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return value;\n    }\n\n    /**\n     * @return The address of the interest rate module.\n     */\n    function interestRateModule(IIonPool pool) external view returns (address) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.AddressSlot storage ptr = $.interestRateModule;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return address(uint160(value));\n    }\n\n    function whitelist(IIonPool pool) external view returns (address) {\n        IonPoolStorage storage $ = _getIonPoolStorage();\n        StorageSlot.AddressSlot storage ptr = $.whitelist;\n\n        uint256 slot;\n        assembly {\n            slot := ptr.slot\n        }\n\n        uint256 value = queryPoolSlot(pool, slot);\n        return address(uint160(value));\n    }\n}\n"
      },
      "src/interfaces/IIonPool.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface IIonPool {\n    error AccessControlBadConfirmation();\n    error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);\n    error AccessControlEnforcedDefaultAdminRules();\n    error AccessControlInvalidDefaultAdmin(address defaultAdmin);\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n    error AddressEmptyCode(address target);\n    error AddressInsufficientBalance(address account);\n    error ArithmeticError();\n    error CeilingExceeded(uint256 newDebt, uint256 debtCeiling);\n    error DepositSurpassesSupplyCap(uint256 depositAmount, uint256 supplyCap);\n    error EnforcedPause();\n    error ExpectedPause();\n    error FailedInnerCall();\n    error GemTransferWithoutConsent(uint8 ilkIndex, address user, address unconsentedOperator);\n    error IlkAlreadyAdded(address ilkAddress);\n    error IlkNotInitialized(uint256 ilkIndex);\n    error InsufficientBalance(address account, uint256 balance, uint256 needed);\n    error InvalidBurnAmount();\n    error InvalidIlkAddress();\n    error InvalidInitialization();\n    error InvalidInterestRateModule(address invalidInterestRateModule);\n    error InvalidMintAmount();\n    error InvalidReceiver(address receiver);\n    error InvalidSender(address sender);\n    error InvalidTreasuryAddress();\n    error InvalidUnderlyingAddress();\n    error InvalidWhitelist();\n    error MathOverflowedMulDiv();\n    error MaxIlksReached();\n    error NotInitializing();\n    error NotScalingUp(uint256 from, uint256 to);\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n    error SafeCastOverflowedUintToInt(uint256 value);\n    error SafeERC20FailedOperation(address token);\n    error TakingWethWithoutConsent(address payer, address unconsentedOperator);\n    error UnsafePositionChange(uint256 newTotalDebtInVault, uint256 collateral, uint256 spot);\n    error UnsafePositionChangeWithoutConsent(uint8 ilkIndex, address user, address unconsentedOperator);\n    error UseOfCollateralWithoutConsent(uint8 ilkIndex, address depositor, address unconsentedOperator);\n    error VaultCannotBeDusty(uint256 amountLeft, uint256 dust);\n\n    event AddOperator(address indexed user, address indexed operator);\n    event Borrow(\n        uint8 indexed ilkIndex,\n        address indexed user,\n        address indexed recipient,\n        uint256 amountOfNormalizedDebt,\n        uint256 ilkRate,\n        uint256 totalDebt\n    );\n    event ConfiscateVault(\n        uint8 indexed ilkIndex,\n        address indexed u,\n        address v,\n        address indexed w,\n        int256 changeInCollateral,\n        int256 changeInNormalizedDebt\n    );\n    event DefaultAdminDelayChangeCanceled();\n    event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);\n    event DefaultAdminTransferCanceled();\n    event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);\n    event DepositCollateral(uint8 indexed ilkIndex, address indexed user, address indexed depositor, uint256 amount);\n    event IlkDebtCeilingUpdated(uint8 indexed ilkIndex, uint256 newDebtCeiling);\n    event IlkDustUpdated(uint8 indexed ilkIndex, uint256 newDust);\n    event IlkInitialized(uint8 indexed ilkIndex, address indexed ilkAddress);\n    event IlkSpotUpdated(uint8 indexed ilkIndex, address newSpot);\n    event Initialized(uint64 version);\n    event InterestRateModuleUpdated(address newModule);\n    event MintAndBurnGem(uint8 indexed ilkIndex, address indexed usr, int256 wad);\n    event MintToTreasury(address indexed treasury, uint256 amount, uint256 supplyFactor);\n    event Paused(address account);\n    event RemoveOperator(address indexed user, address indexed operator);\n    event Repay(\n        uint8 indexed ilkIndex,\n        address indexed user,\n        address indexed payer,\n        uint256 amountOfNormalizedDebt,\n        uint256 ilkRate,\n        uint256 totalDebt\n    );\n    event RepayBadDebt(address indexed user, address indexed payer, uint256 rad);\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n    event Supply(\n        address indexed user, address indexed underlyingFrom, uint256 amount, uint256 supplyFactor, uint256 newDebt\n    );\n    event SupplyCapUpdated(uint256 newSupplyCap);\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event TransferGem(uint8 indexed ilkIndex, address indexed src, address indexed dst, uint256 wad);\n    event TreasuryUpdate(address treasury);\n    event Unpaused(address account);\n    event WhitelistUpdated(address newWhitelist);\n    event Withdraw(address indexed user, address indexed target, uint256 amount, uint256 supplyFactor, uint256 newDebt);\n    event WithdrawCollateral(uint8 indexed ilkIndex, address indexed user, address indexed recipient, uint256 amount);\n\n    function DEFAULT_ADMIN_ROLE() external view returns (bytes32);\n    function GEM_JOIN_ROLE() external view returns (bytes32);\n    function ION() external view returns (bytes32);\n    function LIQUIDATOR_ROLE() external view returns (bytes32);\n    function PAUSE_ROLE() external view returns (bytes32);\n    function acceptDefaultAdminTransfer() external;\n    function accrueInterest() external returns (uint256 newTotalDebt);\n    function addOperator(address operator) external;\n    function addressContains(address ilk) external view returns (bool);\n    function balanceOf(address user) external view returns (uint256);\n    function beginDefaultAdminTransfer(address newAdmin) external;\n    function borrow(\n        uint8 ilkIndex,\n        address user,\n        address recipient,\n        uint256 amountOfNormalizedDebt,\n        bytes32[] memory proof\n    )\n        external;\n    function calculateRewardAndDebtDistribution()\n        external\n        view\n        returns (\n            uint256 totalSupplyFactorIncrease,\n            uint256 totalTreasuryMintAmount,\n            uint104[] memory rateIncreases,\n            uint256 totalDebtIncrease,\n            uint48[] memory timestampIncreases\n        );\n    function calculateRewardAndDebtDistributionForIlk(uint8 ilkIndex)\n        external\n        view\n        returns (uint104 newRateIncrease, uint48 timestampIncrease);\n    function cancelDefaultAdminTransfer() external;\n    function changeDefaultAdminDelay(uint48 newDelay) external;\n    function collateral(uint8 ilkIndex, address user) external view returns (uint256);\n    function confiscateVault(\n        uint8 ilkIndex,\n        address u,\n        address v,\n        address w,\n        int256 changeInCollateral,\n        int256 changeInNormalizedDebt\n    )\n        external;\n    function debt() external view returns (uint256);\n    function debtCeiling(uint8 ilkIndex) external view returns (uint256);\n    function debtUnaccrued() external view returns (uint256);\n    function decimals() external view returns (uint8);\n    function defaultAdmin() external view returns (address);\n    function defaultAdminDelay() external view returns (uint48);\n    function defaultAdminDelayIncreaseWait() external view returns (uint48);\n    function depositCollateral(\n        uint8 ilkIndex,\n        address user,\n        address depositor,\n        uint256 amount,\n        bytes32[] memory proof\n    )\n        external;\n    function dust(uint8 ilkIndex) external view returns (uint256);\n    function gem(uint8 ilkIndex, address user) external view returns (uint256);\n    function getCurrentBorrowRate(uint8 ilkIndex) external view returns (uint256 borrowRate, uint256 reserveFactor);\n    function getIlkAddress(uint256 ilkIndex) external view returns (address);\n    function getIlkIndex(address ilkAddress) external view returns (uint8);\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n    function grantRole(bytes32 role, address account) external;\n    function hasRole(bytes32 role, address account) external view returns (bool);\n    function ilkCount() external view returns (uint256);\n    function implementation() external view returns (address);\n    function initialize(\n        address _underlying,\n        address _treasury,\n        uint8 decimals_,\n        string memory name_,\n        string memory symbol_,\n        address initialDefaultAdmin,\n        address _interestRateModule,\n        address _whitelist\n    )\n        external;\n    function initializeIlk(address ilkAddress) external;\n    function interestRateModule() external view returns (address);\n    function isAllowed(address user, address operator) external view returns (bool);\n    function isOperator(address user, address operator) external view returns (bool);\n    function lastRateUpdate(uint8 ilkIndex) external view returns (uint256);\n    function mintAndBurnGem(uint8 ilkIndex, address usr, int256 wad) external;\n    function name() external view returns (string memory);\n    function normalizedBalanceOf(address user) external view returns (uint256);\n    function normalizedDebt(uint8 ilkIndex, address user) external view returns (uint256);\n    function normalizedTotalSupply() external view returns (uint256);\n    function normalizedTotalSupplyUnaccrued() external view returns (uint256);\n    function owner() external view returns (address);\n    function pause() external;\n    function paused() external view returns (bool);\n    function pendingDefaultAdmin() external view returns (address newAdmin, uint48 schedule);\n    function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 schedule);\n    function rate(uint8 ilkIndex) external view returns (uint256);\n    function rateUnaccrued(uint8 ilkIndex) external view returns (uint256);\n    function removeOperator(address operator) external;\n    function renounceRole(bytes32 role, address account) external;\n    function repay(uint8 ilkIndex, address user, address payer, uint256 amountOfNormalizedDebt) external;\n    function repayBadDebt(address user, uint256 rad) external;\n    function revokeRole(bytes32 role, address account) external;\n    function rollbackDefaultAdminDelay() external;\n    function spot(uint8 ilkIndex) external view returns (address);\n    function supply(address user, uint256 amount, bytes32[] memory proof) external;\n    function supplyFactor() external view returns (uint256);\n    function supplyFactorUnaccrued() external view returns (uint256);\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n    function symbol() external view returns (string memory);\n    function totalNormalizedDebt(uint8 ilkIndex) external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function totalSupplyUnaccrued() external view returns (uint256);\n    function totalUnbackedDebt() external view returns (uint256);\n    function transferGem(uint8 ilkIndex, address src, address dst, uint256 wad) external;\n    function treasury() external view returns (address);\n    function unbackedDebt(address user) external view returns (uint256);\n    function underlying() external view returns (address);\n    function unpause() external;\n    function updateIlkDebtCeiling(uint8 ilkIndex, uint256 newCeiling) external;\n    function updateIlkDust(uint8 ilkIndex, uint256 newDust) external;\n    function updateIlkSpot(uint8 ilkIndex, address newSpot) external;\n    function updateInterestRateModule(address _interestRateModule) external;\n    function updateSupplyCap(uint256 newSupplyCap) external;\n    function updateTreasury(address newTreasury) external;\n    function updateWhitelist(address _whitelist) external;\n    function vault(uint8 ilkIndex, address user) external view returns (uint256, uint256);\n    function weth() external view returns (uint256);\n    function whitelist() external view returns (address);\n    function withdraw(address receiverOfUnderlying, uint256 amount) external;\n    function withdrawCollateral(uint8 ilkIndex, address user, address recipient, uint256 amount) external;\n\n    function getTotalUnderlyingClaims() external view returns (uint256);\n    function getUnderlyingClaimOf(address user) external view returns (uint256);\n    function extsload(bytes32 slot) external view returns (bytes32);\n    function balanceOfUnaccrued(address user) external view returns (uint256);\n}\n"
      },
      "src/interfaces/IIonLens.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\nimport { IIonPool } from \"./IIonPool.sol\";\n\ninterface IIonLens {\n    function queryPoolSlot(IIonPool pool, uint256 slot) external view returns (uint256 value);\n\n    function ilkCount(IIonPool pool) external view returns (uint256);\n\n    function getIlkIndex(IIonPool pool, address ilkAddress) external view returns (uint8);\n\n    function totalNormalizedDebt(IIonPool pool, uint8 ilkIndex) external view returns (uint256);\n\n    function rateUnaccrued(IIonPool pool, uint8 ilkIndex) external view returns (uint256);\n\n    function lastRateUpdate(IIonPool pool, uint8 ilkIndex) external view returns (uint256);\n\n    function spot(IIonPool pool, uint8 ilkIndex) external view returns (address);\n\n    function debtCeiling(IIonPool pool, uint8 ilkIndex) external view returns (uint256);\n\n    function dust(IIonPool pool, uint8 ilkIndex) external view returns (uint256);\n\n    function gem(IIonPool pool, uint8 ilkIndex, address user) external view returns (uint256);\n\n    function unbackedDebt(IIonPool pool, address unbackedDebtor) external view returns (uint256);\n\n    function isOperator(IIonPool pool, address user, address operator) external view returns (bool);\n\n    function debtUnaccrued(IIonPool pool) external view returns (uint256);\n\n    function debt(IIonPool pool) external view returns (uint256);\n\n    function liquidity(IIonPool pool) external view returns (uint256);\n\n    function supplyCap(IIonPool pool) external view returns (uint256);\n\n    function totalUnbackedDebt(IIonPool pool) external view returns (uint256);\n\n    function interestRateModule(IIonPool pool) external view returns (address);\n\n    function whitelist(IIonPool pool) external view returns (address);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position is the index of the value in the `values` array plus 1.\n        // Position 0 is used to mean a value is not in the set.\n        mapping(bytes32 value => uint256) _positions;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._positions[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We cache the value's position to prevent multiple reads from the same storage slot\n        uint256 position = set._positions[value];\n\n        if (position != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 valueIndex = position - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (valueIndex != lastIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the lastValue to the index where the value to delete is\n                set._values[valueIndex] = lastValue;\n                // Update the tracked position of the lastValue (that was just moved)\n                set._positions[lastValue] = position;\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the tracked position for the deleted slot\n            delete set._positions[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._positions[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        bytes32[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(newImplementation.code.length > 0);\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    struct StringSlot {\n        string value;\n    }\n\n    struct BytesSlot {\n        bytes value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` with member `value` located at `slot`.\n     */\n    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n     */\n    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n     */\n    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n     */\n    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := store.slot\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "@balancer-labs/v2-interfaces/=lib/balancer-v2-monorepo/pkg/interfaces/",
        "@balancer-labs/v2-pool-stable/=lib/balancer-v2-monorepo/pkg/pool-stable/",
        "@chainlink/contracts/=lib/chainlink/contracts/",
        "@uniswap/v3-periphery/=lib/v3-periphery/",
        "@uniswap/v3-core/=lib/v3-core/",
        "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
        "balancer-v2-monorepo/=lib/balancer-v2-monorepo/",
        "chainlink/=lib/chainlink/",
        "ds-test/=lib/forge-safe/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
        "forge-safe/=lib/forge-safe/src/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "solady/=lib/solady/",
        "solidity-stringutils/=lib/forge-safe/lib/surl/lib/solidity-stringutils/",
        "solmate/=lib/forge-safe/lib/solmate/src/",
        "surl/=lib/forge-safe/lib/surl/",
        "v3-core/=lib/v3-core/",
        "v3-periphery/=lib/v3-periphery/contracts/",
        "solarray/=lib/solarray/src/",
        "pendle-core-v2-public/=lib/pendle-core-v2-public/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "shanghai",
      "viaIR": false,
      "libraries": {}
    }
  }}