creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/config/error.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n    error FluidConfigError(uint256 errorId_);\n}\n"
      },
      "contracts/config/errorTypes.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n    /***********************************|\n    |    ExpandPercentConfigHandler     | \n    |__________________________________*/\n\n    /// @notice thrown when an input address is zero\n    uint256 internal constant ExpandPercentConfigHandler__AddressZero = 100001;\n\n    /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n    uint256 internal constant ExpandPercentConfigHandler__Unauthorized = 100002;\n\n    /// @notice thrown when invalid params are passed into a method\n    uint256 internal constant ExpandPercentConfigHandler__InvalidParams = 100003;\n\n    /// @notice thrown when no update is currently needed\n    uint256 internal constant ExpandPercentConfigHandler__NoUpdate = 100004;\n\n    /// @notice thrown when slot is not used, e.g. when borrow token is 0 there is no borrow data\n    uint256 internal constant ExpandPercentConfigHandler__SlotDoesNotExist = 100005;\n\n    /***********************************|\n    |      EthenaRateConfigHandler      | \n    |__________________________________*/\n\n    /// @notice thrown when an input address is zero\n    uint256 internal constant EthenaRateConfigHandler__AddressZero = 100011;\n\n    /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n    uint256 internal constant EthenaRateConfigHandler__Unauthorized = 100012;\n\n    /// @notice thrown when invalid params are passed into a method\n    uint256 internal constant EthenaRateConfigHandler__InvalidParams = 100013;\n\n    /// @notice thrown when no update is currently needed\n    uint256 internal constant EthenaRateConfigHandler__NoUpdate = 100014;\n\n    /***********************************|\n    |       MaxBorrowConfigHandler      | \n    |__________________________________*/\n\n    /// @notice thrown when an input address is zero\n    uint256 internal constant MaxBorrowConfigHandler__AddressZero = 100021;\n\n    /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n    uint256 internal constant MaxBorrowConfigHandler__Unauthorized = 100022;\n\n    /// @notice thrown when invalid params are passed into a method\n    uint256 internal constant MaxBorrowConfigHandler__InvalidParams = 100023;\n\n    /// @notice thrown when no update is currently needed\n    uint256 internal constant MaxBorrowConfigHandler__NoUpdate = 100024;\n}\n"
      },
      "contracts/config/maxBorrowHandler/main.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidLiquidityResolver } from \"../../periphery/resolvers/liquidity/iLiquidityResolver.sol\";\nimport { LiquiditySlotsLink } from \"../../libraries/liquiditySlotsLink.sol\";\nimport { BigMathMinified } from \"../../libraries/bigMathMinified.sol\";\nimport { LiquidityCalcs } from \"../../libraries/liquidityCalcs.sol\";\nimport { IFluidReserveContract } from \"../../reserve/interfaces/iReserveContract.sol\";\nimport { Structs as AdminModuleStructs } from \"../../liquidity/adminModule/structs.sol\";\nimport { Error } from \"../error.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\nabstract contract Constants {\n    IFluidReserveContract public immutable RESERVE_CONTRACT;\n    IFluidLiquidity public immutable LIQUIDITY;\n    IFluidLiquidityResolver public immutable LIQUIDITY_RESOLVER;\n    address public immutable PROTOCOL;\n    address public immutable BORROW_TOKEN;\n\n    /// @dev max utilization of total supply that will be set as max borrow limit. In percent (100 = 1%, 1 = 0.01%)\n    uint256 public immutable MAX_UTILIZATION;\n\n    /// @dev minimum percent difference to trigger an update. In percent (100 = 1%, 1 = 0.01%)\n    uint256 public immutable MIN_UPDATE_DIFF;\n\n    bytes32 internal immutable _LIQUDITY_PROTOCOL_BORROW_SLOT;\n\n    uint256 internal constant MAX_UTILIZATION_PRECISION = 1e4;\n    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xff;\n\n    uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n    uint256 internal constant X14 = 0x3fff;\n    uint256 internal constant X18 = 0x3ffff;\n    uint256 internal constant X24 = 0xffffff;\n}\n\nabstract contract Events {\n    /// @notice emitted when borrow max limit is updated\n    event LogUpdateBorrowMaxDebtCeiling(\n        uint256 totalSupplyNormal,\n        uint256 oldMaxDebtCeilingRaw,\n        uint256 maxDebtCeilingRaw,\n        uint256 borrowExchangePrice\n    );\n}\n\n/// @notice Sets max borrow limit for a protocol on Liquidity based on utilization of total supply of the same borrow token\ncontract FluidMaxBorrowConfigHandler is Constants, Error, Events {\n    /// @dev Validates that an address is not the zero address\n    modifier validAddress(address value_) {\n        if (value_ == address(0)) {\n            revert FluidConfigError(ErrorTypes.MaxBorrowConfigHandler__AddressZero);\n        }\n        _;\n    }\n\n    /// @dev Validates that an address is a rebalancer (taken from reserve contract)\n    modifier onlyRebalancer() {\n        if (!RESERVE_CONTRACT.isRebalancer(msg.sender)) {\n            revert FluidConfigError(ErrorTypes.MaxBorrowConfigHandler__Unauthorized);\n        }\n        _;\n    }\n\n    constructor(\n        IFluidReserveContract reserveContract_,\n        IFluidLiquidity liquidity_,\n        IFluidLiquidityResolver liquidityResolver_,\n        address protocol_,\n        address borrowToken_,\n        uint256 maxUtilization_,\n        uint256 minUpdateDiff_\n    )\n        validAddress(address(reserveContract_))\n        validAddress(address(liquidity_))\n        validAddress(address(liquidityResolver_))\n        validAddress(protocol_)\n        validAddress(borrowToken_)\n    {\n        RESERVE_CONTRACT = reserveContract_;\n        LIQUIDITY = liquidity_;\n        LIQUIDITY_RESOLVER = liquidityResolver_;\n        PROTOCOL = protocol_;\n        BORROW_TOKEN = borrowToken_;\n\n        if (maxUtilization_ > MAX_UTILIZATION_PRECISION || minUpdateDiff_ == 0) {\n            revert FluidConfigError(ErrorTypes.MaxBorrowConfigHandler__InvalidParams);\n        }\n\n        _LIQUDITY_PROTOCOL_BORROW_SLOT = LiquiditySlotsLink.calculateDoubleMappingStorageSlot(\n            LiquiditySlotsLink.LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT,\n            protocol_,\n            borrowToken_\n        );\n\n        MAX_UTILIZATION = maxUtilization_;\n        MIN_UPDATE_DIFF = minUpdateDiff_;\n    }\n\n    /// @notice returns `BORROW_TOKEN` total supply at Liquidity (in normal).\n    function getTotalSupply() public view returns (uint256 totalSupplyNormal_) {\n        (totalSupplyNormal_, ) = _getTotalSupply();\n    }\n\n    /// @notice returns the currently set max debt ceiling (in raw for mode with interest!).\n    function currentMaxDebtCeiling() public view returns (uint256 maxDebtCeiling_) {\n        return\n            BigMathMinified.fromBigNumber(\n                (LIQUIDITY.readFromStorage(_LIQUDITY_PROTOCOL_BORROW_SLOT) >>\n                    LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18,\n                DEFAULT_EXPONENT_SIZE,\n                DEFAULT_EXPONENT_MASK\n            );\n    }\n\n    /// @notice returns the max debt ceiling that should be set according to current state (in normal).\n    function calcMaxDebtCeilingNormal() public view returns (uint256 maxDebtCeilingNormal_) {\n        (uint256 maxDebtCeilingRaw_, , uint256 borrowExchangePrice_, , ) = _calcMaxDebtCeiling();\n        // convert to normal\n        maxDebtCeilingNormal_ = (maxDebtCeilingRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION;\n    }\n\n    /// @notice returns the max debt ceiling that should be set according to current state (in raw for mode with interest!).\n    function calcMaxDebtCeiling() public view returns (uint256 maxDebtCeiling_) {\n        (maxDebtCeiling_, , , , ) = _calcMaxDebtCeiling();\n    }\n\n    /// @notice returns how much new config would be different from current config in percent (100 = 1%, 1 = 0.01%).\n    function configPercentDiff() public view returns (uint256 configPercentDiff_) {\n        (uint256 maxDebtCeilingRaw_, , , uint256 userBorrowData_, ) = _calcMaxDebtCeiling();\n\n        (configPercentDiff_, ) = _configPercentDiff(userBorrowData_, maxDebtCeilingRaw_);\n    }\n\n    /// @notice Rebalances the configs for `PROTOCOL` at Fluid Liquidity based on protocol total supply & total borrow.\n    /// Emits `LogUpdateBorrowMaxDebtCeiling` if update is executed.\n    /// Reverts if no update is needed.\n    /// Can only be called by an authorized rebalancer.\n    function rebalance() external onlyRebalancer {\n        if (!_updateBorrowLimits()) {\n            revert FluidConfigError(ErrorTypes.MaxBorrowConfigHandler__NoUpdate);\n        }\n    }\n\n    /***********************************|\n    |            INTERNALS              | \n    |__________________________________*/\n\n    function _getTotalSupply() public view returns (uint256 totalSupplyNormal_, uint256 borrowExchangePrice_) {\n        uint256 supplyExchangePrice_;\n\n        (supplyExchangePrice_, borrowExchangePrice_) = LiquidityCalcs.calcExchangePrices(\n            LIQUIDITY_RESOLVER.getExchangePricesAndConfig(BORROW_TOKEN)\n        );\n\n        totalSupplyNormal_ = LiquidityCalcs.getTotalSupply(\n            LIQUIDITY_RESOLVER.getTotalAmounts(BORROW_TOKEN),\n            supplyExchangePrice_\n        );\n    }\n\n    function _calcMaxDebtCeiling()\n        internal\n        view\n        returns (\n            uint256 maxDebtCeilingRaw_,\n            uint256 totalSupplyNormal_,\n            uint256 borrowExchangePrice_,\n            uint256 userBorrowData_,\n            uint256 baseDebtCeilingRaw_\n        )\n    {\n        (totalSupplyNormal_, borrowExchangePrice_) = _getTotalSupply();\n\n        uint256 maxDebtCeilingNormal_ = (MAX_UTILIZATION * totalSupplyNormal_) / MAX_UTILIZATION_PRECISION;\n\n        // turn into maxDebtCeiling Raw\n        maxDebtCeilingRaw_ = (maxDebtCeilingNormal_ * EXCHANGE_PRICES_PRECISION) / borrowExchangePrice_;\n\n        userBorrowData_ = LIQUIDITY.readFromStorage(_LIQUDITY_PROTOCOL_BORROW_SLOT); // total storage slot\n\n        baseDebtCeilingRaw_ = BigMathMinified.fromBigNumber(\n            (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18,\n            DEFAULT_EXPONENT_SIZE,\n            DEFAULT_EXPONENT_MASK\n        );\n\n        if (baseDebtCeilingRaw_ > maxDebtCeilingRaw_) {\n            // max debt ceiling can never be < base debt ceiling\n            maxDebtCeilingRaw_ = baseDebtCeilingRaw_;\n        }\n    }\n\n    function _configPercentDiff(\n        uint256 userBorrowData_,\n        uint256 maxDebtCeilingRaw_\n    ) internal pure returns (uint256 configPercentDiff_, uint256 oldMaxDebtCeilingRaw_) {\n        oldMaxDebtCeilingRaw_ = BigMathMinified.fromBigNumber(\n            (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18,\n            DEFAULT_EXPONENT_SIZE,\n            DEFAULT_EXPONENT_MASK\n        );\n\n        if (oldMaxDebtCeilingRaw_ == maxDebtCeilingRaw_) {\n            return (0, oldMaxDebtCeilingRaw_);\n        }\n\n        if (oldMaxDebtCeilingRaw_ > maxDebtCeilingRaw_) {\n            // % of how much new max debt ceiling would be smaller\n            configPercentDiff_ = oldMaxDebtCeilingRaw_ - maxDebtCeilingRaw_;\n            // e.g. 10 - 8 = 2. 2 * 10000 / 10 -> 2000 (20%)\n        } else {\n            // % of how much new max debt ceiling would be bigger\n            configPercentDiff_ = maxDebtCeilingRaw_ - oldMaxDebtCeilingRaw_;\n            // e.g. 10 - 8 = 2. 2 * 10000 / 8 -> 2500 (25%)\n        }\n\n        configPercentDiff_ = (configPercentDiff_ * 1e4) / oldMaxDebtCeilingRaw_;\n    }\n\n    function _updateBorrowLimits() internal returns (bool updated_) {\n        (\n            uint256 maxDebtCeilingRaw_,\n            uint256 totalSupplyNormal_,\n            uint256 borrowExchangePrice_,\n            uint256 userBorrowData_,\n            uint256 baseDebtCeilingRaw_\n        ) = _calcMaxDebtCeiling();\n\n        (uint256 configPercentDiff_, uint256 oldMaxDebtCeilingRaw_) = _configPercentDiff(\n            userBorrowData_,\n            maxDebtCeilingRaw_\n        );\n\n        // check if min config deviation is reached\n        if (configPercentDiff_ < MIN_UPDATE_DIFF) {\n            return false;\n        }\n\n        // execute update at Liquidity\n        AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_ = new AdminModuleStructs.UserBorrowConfig[](1);\n        userBorrowConfigs_[0] = AdminModuleStructs.UserBorrowConfig({\n            user: PROTOCOL,\n            token: BORROW_TOKEN,\n            mode: uint8(userBorrowData_ & 1), // first bit\n            expandPercent: (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14, // set same as old\n            expandDuration: (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24, // set same as old\n            baseDebtCeiling: baseDebtCeilingRaw_, // set same as old\n            maxDebtCeiling: maxDebtCeilingRaw_\n        });\n        LIQUIDITY.updateUserBorrowConfigs(userBorrowConfigs_);\n\n        emit LogUpdateBorrowMaxDebtCeiling(\n            totalSupplyNormal_,\n            oldMaxDebtCeilingRaw_,\n            maxDebtCeilingRaw_,\n            borrowExchangePrice_\n        );\n\n        return true;\n    }\n}\n"
      },
      "contracts/infiniteProxy/interfaces/iProxy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IProxy {\n    function setAdmin(address newAdmin_) external;\n\n    function setDummyImplementation(address newDummyImplementation_) external;\n\n    function addImplementation(address implementation_, bytes4[] calldata sigs_) external;\n\n    function removeImplementation(address implementation_) external;\n\n    function getAdmin() external view returns (address);\n\n    function getDummyImplementation() external view returns (address);\n\n    function getImplementationSigs(address impl_) external view returns (bytes4[] memory);\n\n    function getSigsImplementation(bytes4 sig_) external view returns (address);\n\n    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n"
      },
      "contracts/libraries/bigMathMinified.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.\n/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision\n/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can\n/// result in significant gas cost reduction due to storage space reduction.\n/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.\n/// @dev roundUp is more like a increase 1, which happens everytime for the same number.\n/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.\nlibrary BigMathMinified {\n    /// @dev constants to use for `roundUp` input param to increase readability\n    bool internal constant ROUND_DOWN = false;\n    bool internal constant ROUND_UP = true;\n\n    /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).\n    /// e.g.:\n    /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]\n    /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)\n    ///                                     => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000\n    ///                                                                        ^-------------------- 51(exponent) -------------- ^\n    /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011               (2236301563)\n    /// exponent =                                            0011,0011     (51)\n    /// bigNumber =   1000,0101,0100,1011,0100,0000,1111,1011,0011,0011     (572493200179)\n    ///\n    /// @param normal number which needs to be converted into Big Number\n    /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))\n    /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))\n    /// @param roundUp signals if result should be rounded down or up\n    /// @return bigNumber converted bigNumber (coefficient << exponent)\n    function toBigNumber(\n        uint256 normal,\n        uint256 coefficientSize,\n        uint256 exponentSize,\n        bool roundUp\n    ) internal pure returns (uint256 bigNumber) {\n        assembly {\n            let lastBit_\n            let number_ := normal\n            if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n                number_ := shr(0x80, number_)\n                lastBit_ := 0x80\n            }\n            if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n                number_ := shr(0x40, number_)\n                lastBit_ := add(lastBit_, 0x40)\n            }\n            if gt(number_, 0xFFFFFFFF) {\n                number_ := shr(0x20, number_)\n                lastBit_ := add(lastBit_, 0x20)\n            }\n            if gt(number_, 0xFFFF) {\n                number_ := shr(0x10, number_)\n                lastBit_ := add(lastBit_, 0x10)\n            }\n            if gt(number_, 0xFF) {\n                number_ := shr(0x8, number_)\n                lastBit_ := add(lastBit_, 0x8)\n            }\n            if gt(number_, 0xF) {\n                number_ := shr(0x4, number_)\n                lastBit_ := add(lastBit_, 0x4)\n            }\n            if gt(number_, 0x3) {\n                number_ := shr(0x2, number_)\n                lastBit_ := add(lastBit_, 0x2)\n            }\n            if gt(number_, 0x1) {\n                lastBit_ := add(lastBit_, 1)\n            }\n            if gt(number_, 0) {\n                lastBit_ := add(lastBit_, 1)\n            }\n            if lt(lastBit_, coefficientSize) {\n                // for throw exception\n                lastBit_ := coefficientSize\n            }\n            let exponent := sub(lastBit_, coefficientSize)\n            let coefficient := shr(exponent, normal)\n            if and(roundUp, gt(exponent, 0)) {\n                // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number\n                coefficient := add(coefficient, 1)\n                if eq(shl(coefficientSize, 1), coefficient) {\n                    // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits\n                    // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.\n                    coefficient := shl(sub(coefficientSize, 1), 1)\n                    exponent := add(exponent, 1)\n                }\n            }\n            if iszero(lt(exponent, shl(exponentSize, 1))) {\n                // if exponent is >= exponentSize, the normal number is too big to fit within\n                // BigNumber with too small sizes for coefficient and exponent\n                revert(0, 0)\n            }\n            bigNumber := shl(exponentSize, coefficient)\n            bigNumber := add(bigNumber, exponent)\n        }\n    }\n\n    /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`\n    function fromBigNumber(\n        uint256 bigNumber,\n        uint256 exponentSize,\n        uint256 exponentMask\n    ) internal pure returns (uint256 normal) {\n        assembly {\n            let coefficient := shr(exponentSize, bigNumber)\n            let exponent := and(bigNumber, exponentMask)\n            normal := shl(exponent, coefficient)\n        }\n    }\n\n    /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).\n    /// e.g.\n    /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111\n    /// lastBit =                   ^---------------------------------   83   ----------------------------------------^\n    function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {\n        assembly {\n            let number_ := normal\n            if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n                number_ := shr(0x80, number_)\n                lastBit := 0x80\n            }\n            if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n                number_ := shr(0x40, number_)\n                lastBit := add(lastBit, 0x40)\n            }\n            if gt(number_, 0xFFFFFFFF) {\n                number_ := shr(0x20, number_)\n                lastBit := add(lastBit, 0x20)\n            }\n            if gt(number_, 0xFFFF) {\n                number_ := shr(0x10, number_)\n                lastBit := add(lastBit, 0x10)\n            }\n            if gt(number_, 0xFF) {\n                number_ := shr(0x8, number_)\n                lastBit := add(lastBit, 0x8)\n            }\n            if gt(number_, 0xF) {\n                number_ := shr(0x4, number_)\n                lastBit := add(lastBit, 0x4)\n            }\n            if gt(number_, 0x3) {\n                number_ := shr(0x2, number_)\n                lastBit := add(lastBit, 0x2)\n            }\n            if gt(number_, 0x1) {\n                lastBit := add(lastBit, 1)\n            }\n            if gt(number_, 0) {\n                lastBit := add(lastBit, 1)\n            }\n        }\n    }\n}\n"
      },
      "contracts/libraries/errorTypes.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary LibsErrorTypes {\n    /***********************************|\n    |         LiquidityCalcs            | \n    |__________________________________*/\n\n    /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)\n    uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;\n\n    /// @notice thrown when rate data is set to a version that is not implemented\n    uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;\n\n    /***********************************|\n    |           SafeTransfer            | \n    |__________________________________*/\n\n    /// @notice thrown when safe transfer from for an ERC20 fails\n    uint256 internal constant SafeTransfer__TransferFromFailed = 71001;\n\n    /// @notice thrown when safe transfer for an ERC20 fails\n    uint256 internal constant SafeTransfer__TransferFailed = 71002;\n}\n"
      },
      "contracts/libraries/liquidityCalcs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { LibsErrorTypes as ErrorTypes } from \"./errorTypes.sol\";\nimport { LiquiditySlotsLink } from \"./liquiditySlotsLink.sol\";\nimport { BigMathMinified } from \"./bigMathMinified.sol\";\n\n/// @notice implements calculation methods used for Fluid liquidity such as updated exchange prices,\n/// borrow rate, withdrawal / borrow limits, revenue amount.\nlibrary LiquidityCalcs {\n    error FluidLiquidityCalcsError(uint256 errorId_);\n\n    /// @notice emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535\n    event BorrowRateMaxCap();\n\n    /// @dev constants as from Liquidity variables.sol\n    uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n    /// @dev Ignoring leap years\n    uint256 internal constant SECONDS_PER_YEAR = 365 days;\n    // constants used for BigMath conversion from and to storage\n    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\n\n    uint256 internal constant FOUR_DECIMALS = 1e4;\n    uint256 internal constant TWELVE_DECIMALS = 1e12;\n    uint256 internal constant X14 = 0x3fff;\n    uint256 internal constant X15 = 0x7fff;\n    uint256 internal constant X16 = 0xffff;\n    uint256 internal constant X18 = 0x3ffff;\n    uint256 internal constant X24 = 0xffffff;\n    uint256 internal constant X33 = 0x1ffffffff;\n    uint256 internal constant X64 = 0xffffffffffffffff;\n\n    ///////////////////////////////////////////////////////////////////////////\n    //////////                  CALC EXCHANGE PRICES                  /////////\n    ///////////////////////////////////////////////////////////////////////////\n\n    /// @dev calculates interest (exchange prices) for a token given its' exchangePricesAndConfig from storage.\n    /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n    /// @return supplyExchangePrice_ updated supplyExchangePrice\n    /// @return borrowExchangePrice_ updated borrowExchangePrice\n    function calcExchangePrices(\n        uint256 exchangePricesAndConfig_\n    ) internal view returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {\n        // Extracting exchange prices\n        supplyExchangePrice_ =\n            (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &\n            X64;\n        borrowExchangePrice_ =\n            (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &\n            X64;\n\n        if (supplyExchangePrice_ == 0 || borrowExchangePrice_ == 0) {\n            revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__ExchangePriceZero);\n        }\n\n        uint256 temp_ = exchangePricesAndConfig_ & X16; // temp_ = borrowRate\n\n        unchecked {\n            // last timestamp can not be > current timestamp\n            uint256 secondsSinceLastUpdate_ = block.timestamp -\n                ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33);\n\n            uint256 borrowRatio_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\n                X15;\n            if (secondsSinceLastUpdate_ == 0 || temp_ == 0 || borrowRatio_ == 1) {\n                // if no time passed, borrow rate is 0, or no raw borrowings: no exchange price update needed\n                // (if borrowRatio_ == 1 means there is only borrowInterestFree, as first bit is 1 and rest is 0)\n                return (supplyExchangePrice_, borrowExchangePrice_);\n            }\n\n            // calculate new borrow exchange price.\n            // formula borrowExchangePriceIncrease: previous price * borrow rate * secondsSinceLastUpdate_.\n            // nominator is max uint112 (uint64 * uint16 * uint32). Divisor can not be 0.\n            borrowExchangePrice_ +=\n                (borrowExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n                (SECONDS_PER_YEAR * FOUR_DECIMALS);\n\n            // FOR SUPPLY EXCHANGE PRICE:\n            // all yield paid by borrowers (in mode with interest) goes to suppliers in mode with interest.\n            // formula: previous price * supply rate * secondsSinceLastUpdate_.\n            // where supply rate = (borrow rate  - revenueFee%) * ratioSupplyYield. And\n            // ratioSupplyYield = utilization * supplyRatio * borrowRatio\n            //\n            // Example:\n            // supplyRawInterest is 80, supplyInterestFree is 20. totalSupply is 100. BorrowedRawInterest is 50.\n            // BorrowInterestFree is 10. TotalBorrow is 60. borrow rate 40%, revenueFee 10%.\n            // yield is 10 (so half a year must have passed).\n            // supplyRawInterest must become worth 89. totalSupply must become 109. BorrowedRawInterest must become 60.\n            // borrowInterestFree must still be 10. supplyInterestFree still 20. totalBorrow 70.\n            // supplyExchangePrice would have to go from 1 to 1,125 (+ 0.125). borrowExchangePrice from 1 to 1,2 (+0.2).\n            // utilization is 60%. supplyRatio = 20 / 80 = 25% (only 80% of lenders receiving yield).\n            // borrowRatio = 10 / 50 = 20% (only 83,333% of borrowers paying yield):\n            // x of borrowers paying yield = 100% - (20 / (100 + 20)) = 100% - 16.6666666% = 83,333%.\n            // ratioSupplyYield = 60% * 83,33333% * (100% + 20%) = 62,5%\n            // supplyRate = (40% * (100% - 10%)) * = 36% * 62,5% = 22.5%\n            // increase in supplyExchangePrice, assuming 100 as previous price.\n            // 100 * 22,5% * 1/2 (half a year) = 0,1125.\n            // cross-check supplyRawInterest worth = 80 * 1.1125 = 89. totalSupply worth = 89 + 20.\n\n            // -------------- 1. calculate ratioSupplyYield --------------------------------\n            // step1: utilization * supplyRatio (or actually part of lenders receiving yield)\n\n            // temp_ => supplyRatio (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n            // if first bit 0 then ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n            // else ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n            temp_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & X15;\n\n            if (temp_ == 1) {\n                // if no raw supply: no exchange price update needed\n                // (if supplyRatio_ == 1 means there is only supplyInterestFree, as first bit is 1 and rest is 0)\n                return (supplyExchangePrice_, borrowExchangePrice_);\n            }\n\n            // ratioSupplyYield precision is 1e27 as 100% for increased precision when supplyInterestFree > supplyWithInterest\n            if (temp_ & 1 == 1) {\n                // ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n                temp_ = temp_ >> 1;\n\n                // Note: case where temp_ == 0 (only supplyInterestFree, no yield) already covered by early return\n                // in the if statement a little above.\n\n                // based on above example but supplyRawInterest is 20, supplyInterestFree is 80. no fee.\n                // supplyRawInterest must become worth 30. totalSupply must become 110.\n                // supplyExchangePrice would have to go from 1 to 1,5. borrowExchangePrice from 1 to 1,2.\n                // so ratioSupplyYield must come out as 2.5 (250%).\n                // supplyRatio would be (20 * 10_000 / 80) = 2500. but must be inverted.\n                temp_ = (1e27 * FOUR_DECIMALS) / temp_; // e.g. 1e31 / 2500 = 4e27. (* 1e27 for precision)\n                // e.g. 5_000 * (1e27 + 4e27) / 1e27 = 25_000 (=250%).\n                temp_ =\n                    // utilization * (100% + 100% / supplyRatio)\n                    (((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) *\n                        (1e27 + temp_)) / // extract utilization (max 16_383 so there is no way this can overflow).\n                    (FOUR_DECIMALS);\n                // max possible value of temp_ here is 16383 * (1e27 + 1e31) / 1e4 = ~1.64e31\n            } else {\n                // ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n                temp_ = temp_ >> 1;\n                // if temp_ == 0 then only supplyWithInterest => full yield. temp_ is already 0\n\n                // e.g. 5_000 * 10_000 + (20 * 10_000 / 80) / 10_000 = 5000 * 12500 / 10000 = 6250 (=62.5%).\n                temp_ =\n                    // 1e27 * utilization * (100% + supplyRatio) / 100%\n                    (1e27 *\n                        ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) * // extract utilization (max 16_383 so there is no way this can overflow).\n                        (FOUR_DECIMALS + temp_)) /\n                    (FOUR_DECIMALS * FOUR_DECIMALS);\n                // max possible temp_ value: 1e27 * 16383 * 2e4 / 1e8 = 3.2766e27\n            }\n            // from here temp_ => ratioSupplyYield (utilization * supplyRatio part) scaled by 1e27. max possible value ~1.64e31\n\n            // step2 of ratioSupplyYield: add borrowRatio (only x% of borrowers paying yield)\n            if (borrowRatio_ & 1 == 1) {\n                // ratio is borrowWithInterest / borrowInterestFree (borrowInterestFree is bigger)\n                borrowRatio_ = borrowRatio_ >> 1;\n                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n\n                // Note: case where borrowRatio_ == 0 (only borrowInterestFree, no yield) already covered\n                // at the beginning of the method by early return if `borrowRatio_ == 1`.\n\n                // based on above example but borrowRawInterest is 10, borrowInterestFree is 50. no fee. borrowRatio = 20%.\n                // so only 16.66% of borrowers are paying yield. so the 100% - part of the formula is not needed.\n                // x of borrowers paying yield = (borrowRatio / (100 + borrowRatio)) = 16.6666666%\n                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n                borrowRatio_ = (borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_);\n                // max value here for borrowRatio_ is (1e31 / (1e4 + 1e4))= 5e26 (= 50% of borrowers paying yield).\n            } else {\n                // ratio is borrowInterestFree / borrowWithInterest (borrowWithInterest is bigger)\n                borrowRatio_ = borrowRatio_ >> 1;\n\n                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n                // x of borrowers paying yield = 100% - (borrowRatio / (100 + borrowRatio)) = 100% - 16.6666666% = 83,333%.\n                borrowRatio_ = (1e27 - ((borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_)));\n                // borrowRatio can never be > 100%. so max subtraction can be 100% - 100% / 200%.\n                // or if borrowRatio_ is 0 -> 100% - 0. or if borrowRatio_ is 1 -> 100% - 1 / 101.\n                // max value here for borrowRatio_ is 1e27 - 0 = 1e27 (= 100% of borrowers paying yield).\n            }\n\n            // temp_ => ratioSupplyYield. scaled down from 1e25 = 1% each to normal percent precision 1e2 = 1%.\n            // max nominator value is ~1.64e31 * 1e27 = 1.64e58. max result = 1.64e8\n            temp_ = (FOUR_DECIMALS * temp_ * borrowRatio_) / 1e54;\n\n            // 2. calculate supply rate\n            // temp_ => supply rate (borrow rate  - revenueFee%) * ratioSupplyYield.\n            // division part is done in next step to increase precision. (divided by 2x FOUR_DECIMALS, fee + borrowRate)\n            // Note that all calculation divisions for supplyExchangePrice are rounded down.\n            // Note supply rate can be bigger than the borrowRate, e.g. if there are only few lenders with interest\n            // but more suppliers not earning interest.\n            temp_ = ((exchangePricesAndConfig_ & X16) * // borrow rate\n                temp_ * // ratioSupplyYield\n                (FOUR_DECIMALS - ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14))); // revenueFee\n            // fee can not be > 100%. max possible = 65535 * ~1.64e8 * 1e4 =~1.074774e17.\n\n            // 3. calculate increase in supply exchange price\n            supplyExchangePrice_ += ((supplyExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n                (SECONDS_PER_YEAR * FOUR_DECIMALS * FOUR_DECIMALS * FOUR_DECIMALS));\n            // max possible nominator = max uint 64 * 1.074774e17 * max uint32 = ~8.52e45. Denominator can not be 0.\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    //////////                     CALC REVENUE                       /////////\n    ///////////////////////////////////////////////////////////////////////////\n\n    /// @dev gets the `revenueAmount_` for a token given its' totalAmounts and exchangePricesAndConfig from storage\n    /// and the current balance of the Fluid liquidity contract for the token.\n    /// @param totalAmounts_ total amounts packed uint256 read from storage\n    /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n    /// @param liquidityTokenBalance_   current balance of Liquidity contract (IERC20(token_).balanceOf(address(this)))\n    /// @return revenueAmount_ collectable revenue amount\n    function calcRevenue(\n        uint256 totalAmounts_,\n        uint256 exchangePricesAndConfig_,\n        uint256 liquidityTokenBalance_\n    ) internal view returns (uint256 revenueAmount_) {\n        // @dev no need to super-optimize this method as it is only used by admin\n\n        // calculate the new exchange prices based on earned interest\n        (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = calcExchangePrices(exchangePricesAndConfig_);\n\n        // total supply = interest free + with interest converted from raw\n        uint256 totalSupply_ = getTotalSupply(totalAmounts_, supplyExchangePrice_);\n\n        if (totalSupply_ > 0) {\n            // available revenue: balanceOf(token) + totalBorrowings - totalLendings.\n            revenueAmount_ = liquidityTokenBalance_ + getTotalBorrow(totalAmounts_, borrowExchangePrice_);\n            // ensure there is no possible case because of rounding etc. where this would revert,\n            // explicitly check if >\n            revenueAmount_ = revenueAmount_ > totalSupply_ ? revenueAmount_ - totalSupply_ : 0;\n            // Note: if utilization > 100% (totalSupply < totalBorrow), then all the amount above 100% utilization\n            // can only be revenue.\n        } else {\n            // if supply is 0, then rest of balance can be withdrawn as revenue so that no amounts get stuck\n            revenueAmount_ = liquidityTokenBalance_;\n        }\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    //////////                      CALC LIMITS                       /////////\n    ///////////////////////////////////////////////////////////////////////////\n\n    /// @dev calculates withdrawal limit before an operate execution:\n    /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n    /// @param userSupplyData_ user supply data packed uint256 from storage\n    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath\n    /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.\n    ///         returned value is in raw for with interest mode, normal amount for interest free mode!\n    function calcWithdrawalLimitBeforeOperate(\n        uint256 userSupplyData_,\n        uint256 userSupply_\n    ) internal view returns (uint256 currentWithdrawalLimit_) {\n        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).\n        // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.\n        // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be\n        // a deposit anyway. Important is that it would not revert.\n\n        // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit\n        // is the fully expanded limit immediately.\n\n        // extract last set withdrawal limit\n        uint256 lastWithdrawalLimit_ = (userSupplyData_ >>\n            LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) & X64;\n        lastWithdrawalLimit_ =\n            (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n            (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);\n        if (lastWithdrawalLimit_ == 0) {\n            // withdrawal limit is not activated. Max withdrawal allowed\n            return 0;\n        }\n\n        uint256 maxWithdrawableLimit_;\n        uint256 temp_;\n        unchecked {\n            // extract max withdrawable percent of user supply and\n            // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed\n            // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.\n\n            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n            maxWithdrawableLimit_ =\n                (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /\n                FOUR_DECIMALS;\n\n            // time elapsed since last withdrawal limit was set (in seconds)\n            // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.\n            // last timestamp can not be > current timestamp\n            temp_ =\n                block.timestamp -\n                ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);\n        }\n        // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.\n        // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.\n        // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.\n        temp_ =\n            (maxWithdrawableLimit_ * temp_) /\n            // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)\n            ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0\n        // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.\n        // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,\n        // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0\n        // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.\n        unchecked {\n            // underflow explicitly checked & handled\n            currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;\n            // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.\n            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n            temp_ = userSupply_ - maxWithdrawableLimit_;\n        }\n        // if withdrawal limit is decreased below minimum then set minimum\n        // (e.g. when more than expandDuration time has elapsed)\n        if (temp_ > currentWithdrawalLimit_) {\n            currentWithdrawalLimit_ = temp_;\n        }\n    }\n\n    /// @dev calculates withdrawal limit after an operate execution:\n    /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n    /// @param userSupplyData_ user supply data packed uint256 from storage\n    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount\n    /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`\n    /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in\n    ///                          raw for with interest mode, normal amount for interest free mode!\n    function calcWithdrawalLimitAfterOperate(\n        uint256 userSupplyData_,\n        uint256 userSupply_,\n        uint256 newWithdrawalLimit_\n    ) internal pure returns (uint256) {\n        // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed\n        uint256 temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;\n        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n        // if user supply is below base limit then max withdrawals are allowed\n        if (userSupply_ < temp_) {\n            return 0;\n        }\n        // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)\n        temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;\n        unchecked {\n            // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))\n            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n            temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);\n        }\n        // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.\n        // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where\n        // increased deposit amount outpaces withrawals.\n        if (temp_ > newWithdrawalLimit_) {\n            return temp_;\n        }\n        return newWithdrawalLimit_;\n    }\n\n    /// @dev calculates borrow limit before an operate execution:\n    /// total amount user borrow can reach (not borrowable amount in current operation).\n    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n    /// @param userBorrowData_ user borrow data packed uint256 from storage\n    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`\n    /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in\n    ///                             raw for with interest mode, normal amount for interest free mode!\n    function calcBorrowLimitBeforeOperate(\n        uint256 userBorrowData_,\n        uint256 userBorrow_\n    ) internal view returns (uint256 currentBorrowLimit_) {\n        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.\n        // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus\n        // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.\n\n        // temp_ = extract borrow expand percent (is in 1e2 decimals)\n        uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;\n\n        uint256 maxExpansionLimit_;\n        uint256 maxExpandedBorrowLimit_;\n        unchecked {\n            // calculate max expansion limit: Max amount limit can expand to since last interaction\n            // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n            maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);\n\n            // calculate max borrow limit: Max point limit can increase to since last interaction\n            maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;\n        }\n\n        // currentBorrowLimit_ = extract base borrow limit\n        currentBorrowLimit_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n        currentBorrowLimit_ =\n            (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n            (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);\n\n        if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {\n            return currentBorrowLimit_;\n        }\n        // time elapsed since last borrow limit was set (in seconds)\n        unchecked {\n            // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)\n            temp_ =\n                block.timestamp -\n                ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last udpate timestamp\n        }\n\n        // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit\n        currentBorrowLimit_ =\n            // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.\n            // divisor is extract expand duration (after this, full expansion to expandPercentage happened).\n            ((maxExpansionLimit_ * temp_) /\n                ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0\n            //  extract last set borrow limit\n            BigMathMinified.fromBigNumber(\n                (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,\n                DEFAULT_EXPONENT_SIZE,\n                DEFAULT_EXPONENT_MASK\n            );\n\n        // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,\n        // so set to `maxExpandedBorrowLimit_` in that case.\n        // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)\n        if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {\n            currentBorrowLimit_ = maxExpandedBorrowLimit_;\n        }\n        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n        if (currentBorrowLimit_ > temp_) {\n            currentBorrowLimit_ = temp_;\n        }\n    }\n\n    /// @dev calculates borrow limit after an operate execution:\n    /// total amount user borrow can reach (not borrowable amount in current operation).\n    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n    /// @param userBorrowData_ user borrow data packed uint256 from storage\n    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount\n    /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`\n    /// @return borrowLimit_ updated borrow limit that should be written to storage.\n    ///                      returned value is in raw for with interest mode, normal amount for interest free mode!\n    function calcBorrowLimitAfterOperate(\n        uint256 userBorrowData_,\n        uint256 userBorrow_,\n        uint256 newBorrowLimit_\n    ) internal pure returns (uint256 borrowLimit_) {\n        // temp_ = extract borrow expand percent\n        uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)\n\n        unchecked {\n            // borrowLimit_ = calculate maximum borrow limit at full expansion.\n            // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n            borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);\n        }\n\n        // temp_ = extract base borrow limit\n        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n        if (borrowLimit_ < temp_) {\n            // below base limit, borrow limit is always base limit\n            return temp_;\n        }\n        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n        // make sure fully expanded borrow limit is not above hard max borrow limit\n        if (borrowLimit_ > temp_) {\n            borrowLimit_ = temp_;\n        }\n        // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.\n        // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)\n        if (newBorrowLimit_ > borrowLimit_) {\n            return borrowLimit_;\n        }\n        return newBorrowLimit_;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    //////////                      CALC RATES                        /////////\n    ///////////////////////////////////////////////////////////////////////////\n\n    /// @dev Calculates new borrow rate from utilization for a token\n    /// @param rateData_ rate data packed uint256 from storage for the token\n    /// @param utilization_ totalBorrow / totalSupply. 1e4 = 100% utilization\n    /// @return rate_ rate for that particular token in 1e2 precision (e.g. 5% rate = 500)\n    function calcBorrowRateFromUtilization(uint256 rateData_, uint256 utilization_) internal returns (uint256 rate_) {\n        // extract rate version: 4 bits (0xF) starting from bit 0\n        uint256 rateVersion_ = (rateData_ & 0xF);\n\n        if (rateVersion_ == 1) {\n            rate_ = calcRateV1(rateData_, utilization_);\n        } else if (rateVersion_ == 2) {\n            rate_ = calcRateV2(rateData_, utilization_);\n        } else {\n            revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__UnsupportedRateVersion);\n        }\n\n        if (rate_ > X16) {\n            // hard cap for borrow rate at maximum value 16 bits (65535) to make sure it does not overflow storage space.\n            // this is unlikely to ever happen if configs stay within expected levels.\n            rate_ = X16;\n            // emit event to more easily become aware\n            emit BorrowRateMaxCap();\n        }\n    }\n\n    /// @dev calculates the borrow rate based on utilization for rate data version 1 (with one kink) in 1e2 precision\n    /// @param rateData_ rate data packed uint256 from storage for the token\n    /// @param utilization_  in 1e2 (100% = 1e4)\n    /// @return rate_ rate in 1e2 precision\n    function calcRateV1(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n        /// For rate v1 (one kink) ------------------------------------------------------\n        /// Next 16  bits =>  4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  52- 67 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Last 188 bits =>  68-255 => blank, might come in use in future\n\n        // y = mx + c.\n        // y is borrow rate\n        // x is utilization\n        // m = slope (m can be 0 but never negative)\n        // c is constant (c can be negative)\n\n        uint256 y1_;\n        uint256 y2_;\n        uint256 x1_;\n        uint256 x2_;\n\n        // extract kink1: 16 bits (0xFFFF) starting from bit 20\n        // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n        uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;\n        if (utilization_ < kink1_) {\n            // if utilization is less than kink\n            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16;\n            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n            x1_ = 0; // 0%\n            x2_ = kink1_;\n        } else {\n            // else utilization is greater than kink\n            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16;\n            x1_ = kink1_;\n            x2_ = FOUR_DECIMALS; // 100%\n        }\n\n        int256 constant_;\n        uint256 slope_;\n        unchecked {\n            // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n            // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n            slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n            // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n            // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n            // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n            // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n            // subtraction most extreme case would be  0 - max value slope_ * x1_ => can not underflow int256\n            constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n            // calculating new borrow rate\n            // - slope_ max value is 65535 * 1e12,\n            // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n            // - constant max value is 65535 * 1e12\n            // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n            // divisor TWELVE_DECIMALS can not be 0\n            rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n        }\n    }\n\n    /// @dev calculates the borrow rate based on utilization for rate data version 2 (with two kinks) in 1e4 precision\n    /// @param rateData_ rate data packed uint256 from storage for the token\n    /// @param utilization_  in 1e2 (100% = 1e4)\n    /// @return rate_ rate in 1e4 precision\n    function calcRateV2(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n        /// For rate v2 (two kinks) -----------------------------------------------------\n        /// Next 16  bits =>  4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  52- 67 => Utilization at kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  68- 83 => Rate at utilization kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Next 16  bits =>  84- 99 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n        /// Last 156 bits => 100-255 => blank, might come in use in future\n\n        // y = mx + c.\n        // y is borrow rate\n        // x is utilization\n        // m = slope (m can be 0 but never negative)\n        // c is constant (c can be negative)\n\n        uint256 y1_;\n        uint256 y2_;\n        uint256 x1_;\n        uint256 x2_;\n\n        // extract kink1: 16 bits (0xFFFF) starting from bit 20\n        // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n        uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16;\n        if (utilization_ < kink1_) {\n            // if utilization is less than kink1\n            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16;\n            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n            x1_ = 0; // 0%\n            x2_ = kink1_;\n        } else {\n            // extract kink2: 16 bits (0xFFFF) starting from bit 52\n            uint256 kink2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16;\n            if (utilization_ < kink2_) {\n                // if utilization is less than kink2\n                y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n                y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n                x1_ = kink1_;\n                x2_ = kink2_;\n            } else {\n                // else utilization is greater than kink2\n                y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n                y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16;\n                x1_ = kink2_;\n                x2_ = FOUR_DECIMALS;\n            }\n        }\n\n        int256 constant_;\n        uint256 slope_;\n        unchecked {\n            // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n            // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n            slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n            // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n            // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n            // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n            // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n            // subtraction most extreme case would be  0 - max value slope_ * x1_ => can not underflow int256\n            constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n            // calculating new borrow rate\n            // - slope_ max value is 65535 * 1e12,\n            // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n            // - constant max value is 65535 * 1e12\n            // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n            // divisor TWELVE_DECIMALS can not be 0\n            rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n        }\n    }\n\n    /// @dev reads the total supply out of Liquidity packed storage `totalAmounts_` for `supplyExchangePrice_`\n    function getTotalSupply(\n        uint256 totalAmounts_,\n        uint256 supplyExchangePrice_\n    ) internal pure returns (uint256 totalSupply_) {\n        // totalSupply_ => supplyInterestFree\n        totalSupply_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n        totalSupply_ = (totalSupply_ >> DEFAULT_EXPONENT_SIZE) << (totalSupply_ & DEFAULT_EXPONENT_MASK);\n\n        uint256 totalSupplyRaw_ = totalAmounts_ & X64; // no shifting as supplyRaw is first 64 bits\n        totalSupplyRaw_ = (totalSupplyRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalSupplyRaw_ & DEFAULT_EXPONENT_MASK);\n\n        // totalSupply = supplyInterestFree + supplyRawInterest normalized from raw\n        totalSupply_ += ((totalSupplyRaw_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n    }\n\n    /// @dev reads the total borrow out of Liquidity packed storage `totalAmounts_` for `borrowExchangePrice_`\n    function getTotalBorrow(\n        uint256 totalAmounts_,\n        uint256 borrowExchangePrice_\n    ) internal pure returns (uint256 totalBorrow_) {\n        // totalBorrow_ => borrowInterestFree\n        // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n        totalBorrow_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n        totalBorrow_ = (totalBorrow_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrow_ & DEFAULT_EXPONENT_MASK);\n\n        uint256 totalBorrowRaw_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n        totalBorrowRaw_ = (totalBorrowRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrowRaw_ & DEFAULT_EXPONENT_MASK);\n\n        // totalBorrow = borrowInterestFree + borrowRawInterest normalized from raw\n        totalBorrow_ += ((totalBorrowRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n    }\n}\n"
      },
      "contracts/libraries/liquiditySlotsLink.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice library that helps in reading / working with storage slot data of Fluid Liquidity.\n/// @dev as all data for Fluid Liquidity is internal, any data must be fetched directly through manual\n/// slot reading through this library or, if gas usage is less important, through the FluidLiquidityResolver.\nlibrary LiquiditySlotsLink {\n    /// @dev storage slot for status at Liquidity\n    uint256 internal constant LIQUIDITY_STATUS_SLOT = 1;\n    /// @dev storage slot for auths mapping at Liquidity\n    uint256 internal constant LIQUIDITY_AUTHS_MAPPING_SLOT = 2;\n    /// @dev storage slot for guardians mapping at Liquidity\n    uint256 internal constant LIQUIDITY_GUARDIANS_MAPPING_SLOT = 3;\n    /// @dev storage slot for user class mapping at Liquidity\n    uint256 internal constant LIQUIDITY_USER_CLASS_MAPPING_SLOT = 4;\n    /// @dev storage slot for exchangePricesAndConfig mapping at Liquidity\n    uint256 internal constant LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT = 5;\n    /// @dev storage slot for rateData mapping at Liquidity\n    uint256 internal constant LIQUIDITY_RATE_DATA_MAPPING_SLOT = 6;\n    /// @dev storage slot for totalAmounts mapping at Liquidity\n    uint256 internal constant LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT = 7;\n    /// @dev storage slot for user supply double mapping at Liquidity\n    uint256 internal constant LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT = 8;\n    /// @dev storage slot for user borrow double mapping at Liquidity\n    uint256 internal constant LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT = 9;\n    /// @dev storage slot for listed tokens array at Liquidity\n    uint256 internal constant LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT = 10;\n\n    // --------------------------------\n    // @dev stacked uint256 storage slots bits position data for each:\n\n    // ExchangePricesAndConfig\n    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATE = 0;\n    uint256 internal constant BITS_EXCHANGE_PRICES_FEE = 16;\n    uint256 internal constant BITS_EXCHANGE_PRICES_UTILIZATION = 30;\n    uint256 internal constant BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD = 44;\n    uint256 internal constant BITS_EXCHANGE_PRICES_LAST_TIMESTAMP = 58;\n    uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE = 91;\n    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE = 155;\n    uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219;\n    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATIO = 234;\n\n    // RateData:\n    uint256 internal constant BITS_RATE_DATA_VERSION = 0;\n    // RateData: V1\n    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO = 4;\n    uint256 internal constant BITS_RATE_DATA_V1_UTILIZATION_AT_KINK = 20;\n    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK = 36;\n    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX = 52;\n    // RateData: V2\n    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO = 4;\n    uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1 = 20;\n    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1 = 36;\n    uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2 = 52;\n    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2 = 68;\n    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX = 84;\n\n    // TotalAmounts\n    uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_WITH_INTEREST = 0;\n    uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE = 64;\n    uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST = 128;\n    uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE = 192;\n\n    // UserSupplyData\n    uint256 internal constant BITS_USER_SUPPLY_MODE = 0;\n    uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;\n    uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;\n    uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;\n    uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;\n    uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;\n    uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;\n    uint256 internal constant BITS_USER_SUPPLY_IS_PAUSED = 255;\n\n    // UserBorrowData\n    uint256 internal constant BITS_USER_BORROW_MODE = 0;\n    uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;\n    uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;\n    uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;\n    uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;\n    uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;\n    uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;\n    uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;\n    uint256 internal constant BITS_USER_BORROW_IS_PAUSED = 255;\n\n    // --------------------------------\n\n    /// @notice Calculating the slot ID for Liquidity contract for single mapping at `slot_` for `key_`\n    function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {\n        return keccak256(abi.encode(key_, slot_));\n    }\n\n    /// @notice Calculating the slot ID for Liquidity contract for double mapping at `slot_` for `key1_` and `key2_`\n    function calculateDoubleMappingStorageSlot(\n        uint256 slot_,\n        address key1_,\n        address key2_\n    ) internal pure returns (bytes32) {\n        bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n        return keccak256(abi.encode(key2_, intermediateSlot_));\n    }\n}\n"
      },
      "contracts/liquidity/adminModule/structs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Structs {\n    struct AddressBool {\n        address addr;\n        bool value;\n    }\n\n    struct AddressUint256 {\n        address addr;\n        uint256 value;\n    }\n\n    /// @notice struct to set borrow rate data for version 1\n    struct RateDataV1Params {\n        ///\n        /// @param token for rate data\n        address token;\n        ///\n        /// @param kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n        /// utilization below kink usually means slow increase in rate, once utilization is above kink borrow rate increases fast\n        uint256 kink;\n        ///\n        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n        /// i.e. constant minimum borrow rate\n        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n        uint256 rateAtUtilizationZero;\n        ///\n        /// @param rateAtUtilizationKink borrow rate when utilization is at kink. in 1e2: 100% = 10_000; 1% = 100\n        /// e.g. when rate should be 7% at kink then rateAtUtilizationKink would be 700\n        uint256 rateAtUtilizationKink;\n        ///\n        /// @param rateAtUtilizationMax borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n        uint256 rateAtUtilizationMax;\n    }\n\n    /// @notice struct to set borrow rate data for version 2\n    struct RateDataV2Params {\n        ///\n        /// @param token for rate data\n        address token;\n        ///\n        /// @param kink1 first kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n        /// utilization below kink 1 usually means slow increase in rate, once utilization is above kink 1 borrow rate increases faster\n        uint256 kink1;\n        ///\n        /// @param kink2 second kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n        /// utilization below kink 2 usually means slow / medium increase in rate, once utilization is above kink 2 borrow rate increases fast\n        uint256 kink2;\n        ///\n        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n        /// i.e. constant minimum borrow rate\n        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n        uint256 rateAtUtilizationZero;\n        ///\n        /// @param rateAtUtilizationKink1 desired borrow rate when utilization is at first kink. in 1e2: 100% = 10_000; 1% = 100\n        /// e.g. when rate should be 7% at first kink then rateAtUtilizationKink would be 700\n        uint256 rateAtUtilizationKink1;\n        ///\n        /// @param rateAtUtilizationKink2 desired borrow rate when utilization is at second kink. in 1e2: 100% = 10_000; 1% = 100\n        /// e.g. when rate should be 7% at second kink then rateAtUtilizationKink would be 1_200\n        uint256 rateAtUtilizationKink2;\n        ///\n        /// @param rateAtUtilizationMax desired borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n        uint256 rateAtUtilizationMax;\n    }\n\n    /// @notice struct to set token config\n    struct TokenConfig {\n        ///\n        /// @param token address\n        address token;\n        ///\n        /// @param fee charges on borrower's interest. in 1e2: 100% = 10_000; 1% = 100\n        uint256 fee;\n        ///\n        /// @param threshold on when to update the storage slot. in 1e2: 100% = 10_000; 1% = 100\n        uint256 threshold;\n    }\n\n    /// @notice struct to set user supply & withdrawal config\n    struct UserSupplyConfig {\n        ///\n        /// @param user address\n        address user;\n        ///\n        /// @param token address\n        address token;\n        ///\n        /// @param mode: 0 = without interest. 1 = with interest\n        uint8 mode;\n        ///\n        /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n        /// Also used to calculate rate at which withdrawal limit should decrease (instant).\n        uint256 expandPercent;\n        ///\n        /// @param expandDuration withdrawal limit expand duration in seconds.\n        /// used to calculate rate together with expandPercent\n        uint256 expandDuration;\n        ///\n        /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.\n        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n        /// with interest -> raw, without interest -> normal\n        uint256 baseWithdrawalLimit;\n    }\n\n    /// @notice struct to set user borrow & payback config\n    struct UserBorrowConfig {\n        ///\n        /// @param user address\n        address user;\n        ///\n        /// @param token address\n        address token;\n        ///\n        /// @param mode: 0 = without interest. 1 = with interest\n        uint8 mode;\n        ///\n        /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n        /// Also used to calculate rate at which debt limit should decrease (instant).\n        uint256 expandPercent;\n        ///\n        /// @param expandDuration debt limit expand duration in seconds.\n        /// used to calculate rate together with expandPercent\n        uint256 expandDuration;\n        ///\n        /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling\n        /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.\n        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n        /// with interest -> raw, without interest -> normal\n        uint256 baseDebtCeiling;\n        ///\n        /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.\n        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n        /// with interest -> raw, without interest -> normal\n        uint256 maxDebtCeiling;\n    }\n}\n"
      },
      "contracts/liquidity/interfaces/iLiquidity.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IProxy } from \"../../infiniteProxy/interfaces/iProxy.sol\";\nimport { Structs as AdminModuleStructs } from \"../adminModule/structs.sol\";\n\ninterface IFluidLiquidityAdmin {\n    /// @notice adds/removes auths. Auths generally could be contracts which can have restricted actions defined on contract.\n    ///         auths can be helpful in reducing governance overhead where it's not needed.\n    /// @param authsStatus_ array of structs setting allowed status for an address.\n    ///                     status true => add auth, false => remove auth\n    function updateAuths(AdminModuleStructs.AddressBool[] calldata authsStatus_) external;\n\n    /// @notice adds/removes guardians. Only callable by Governance.\n    /// @param guardiansStatus_ array of structs setting allowed status for an address.\n    ///                         status true => add guardian, false => remove guardian\n    function updateGuardians(AdminModuleStructs.AddressBool[] calldata guardiansStatus_) external;\n\n    /// @notice changes the revenue collector address (contract that is sent revenue). Only callable by Governance.\n    /// @param revenueCollector_  new revenue collector address\n    function updateRevenueCollector(address revenueCollector_) external;\n\n    /// @notice changes current status, e.g. for pausing or unpausing all user operations. Only callable by Auths.\n    /// @param newStatus_ new status\n    ///        status = 2 -> pause, status = 1 -> resume.\n    function changeStatus(uint256 newStatus_) external;\n\n    /// @notice                  update tokens rate data version 1. Only callable by Auths.\n    /// @param tokensRateData_   array of RateDataV1Params with rate data to set for each token\n    function updateRateDataV1s(AdminModuleStructs.RateDataV1Params[] calldata tokensRateData_) external;\n\n    /// @notice                  update tokens rate data version 2. Only callable by Auths.\n    /// @param tokensRateData_   array of RateDataV2Params with rate data to set for each token\n    function updateRateDataV2s(AdminModuleStructs.RateDataV2Params[] calldata tokensRateData_) external;\n\n    /// @notice updates token configs: fee charge on borrowers interest & storage update utilization threshold.\n    ///         Only callable by Auths.\n    /// @param tokenConfigs_ contains token address, fee & utilization threshold\n    function updateTokenConfigs(AdminModuleStructs.TokenConfig[] calldata tokenConfigs_) external;\n\n    /// @notice updates user classes: 0 is for new protocols, 1 is for established protocols.\n    ///         Only callable by Auths.\n    /// @param userClasses_ struct array of uint256 value to assign for each user address\n    function updateUserClasses(AdminModuleStructs.AddressUint256[] calldata userClasses_) external;\n\n    /// @notice sets user supply configs per token basis. Eg: with interest or interest-free and automated limits.\n    ///         Only callable by Auths.\n    /// @param userSupplyConfigs_ struct array containing user supply config, see `UserSupplyConfig` struct for more info\n    function updateUserSupplyConfigs(AdminModuleStructs.UserSupplyConfig[] memory userSupplyConfigs_) external;\n\n    /// @notice setting user borrow configs per token basis. Eg: with interest or interest-free and automated limits.\n    ///         Only callable by Auths.\n    /// @param userBorrowConfigs_ struct array containing user borrow config, see `UserBorrowConfig` struct for more info\n    function updateUserBorrowConfigs(AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_) external;\n\n    /// @notice pause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n    /// Only callable by Guardians.\n    /// @param user_          address of user to pause operations for\n    /// @param supplyTokens_  token addresses to pause withdrawals for\n    /// @param borrowTokens_  token addresses to pause borrowings for\n    function pauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n    /// @notice unpause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n    /// Only callable by Guardians.\n    /// @param user_          address of user to unpause operations for\n    /// @param supplyTokens_  token addresses to unpause withdrawals for\n    /// @param borrowTokens_  token addresses to unpause borrowings for\n    function unpauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n    /// @notice         collects revenue for tokens to configured revenueCollector address.\n    /// @param tokens_  array of tokens to collect revenue for\n    /// @dev            Note that this can revert if token balance is < revenueAmount (utilization > 100%)\n    function collectRevenue(address[] calldata tokens_) external;\n\n    /// @notice gets the current updated exchange prices for n tokens and updates all prices, rates related data in storage.\n    /// @param tokens_ tokens to update exchange prices for\n    /// @return supplyExchangePrices_ new supply rates of overall system for each token\n    /// @return borrowExchangePrices_ new borrow rates of overall system for each token\n    function updateExchangePrices(\n        address[] calldata tokens_\n    ) external returns (uint256[] memory supplyExchangePrices_, uint256[] memory borrowExchangePrices_);\n}\n\ninterface IFluidLiquidityLogic is IFluidLiquidityAdmin {\n    /// @notice Single function which handles supply, withdraw, borrow & payback\n    /// @param token_ address of token (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native)\n    /// @param supplyAmount_ if +ve then supply, if -ve then withdraw, if 0 then nothing\n    /// @param borrowAmount_ if +ve then borrow, if -ve then payback, if 0 then nothing\n    /// @param withdrawTo_ if withdrawal then to which address\n    /// @param borrowTo_ if borrow then to which address\n    /// @param callbackData_ callback data passed to `liquidityCallback` method of protocol\n    /// @return memVar3_ updated supplyExchangePrice\n    /// @return memVar4_ updated borrowExchangePrice\n    /// @dev to trigger skipping in / out transfers when in&out amounts balance themselves out (gas optimization):\n    /// -   supply(+) == borrow(+), withdraw(-) == payback(-).\n    /// -   `withdrawTo_` / `borrowTo_` must be msg.sender (protocol)\n    /// -   `callbackData_` MUST be encoded so that \"from\" address is at last 20 bytes (if this optimization is desired),\n    ///     also for native token operations where liquidityCallback is not triggered!\n    ///     from address must come at last position if there is more data. I.e. encode like:\n    ///     abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end\n    ///     so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end.\n    function operate(\n        address token_,\n        int256 supplyAmount_,\n        int256 borrowAmount_,\n        address withdrawTo_,\n        address borrowTo_,\n        bytes calldata callbackData_\n    ) external payable returns (uint256 memVar3_, uint256 memVar4_);\n}\n\ninterface IFluidLiquidity is IProxy, IFluidLiquidityLogic {}\n"
      },
      "contracts/periphery/resolvers/liquidity/iLiquidityResolver.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs as LiquidityStructs } from \"../../../periphery/resolvers/liquidity/structs.sol\";\n\ninterface IFluidLiquidityResolver {\n    /// @notice gets the `revenueAmount_` for a `token_`.\n    function getRevenue(address token_) external view returns (uint256 revenueAmount_);\n\n    /// @notice address of contract that gets sent the revenue. Configurable by governance\n    function getRevenueCollector() external view returns (address);\n\n    /// @notice Liquidity contract paused status: status = 1 -> normal. status = 2 -> paused.\n    function getStatus() external view returns (uint256);\n\n    /// @notice checks if `auth_` is an allowed auth on Liquidity.\n    /// Auths can set most config values. E.g. contracts that automate certain flows like e.g. adding a new fToken.\n    /// Governance can add/remove auths. Governance is auth by default.\n    function isAuth(address auth_) external view returns (uint256);\n\n    /// @notice checks if `guardian_` is an allowed Guardian on Liquidity.\n    /// Guardians can pause lower class users.\n    /// Governance can add/remove guardians. Governance is guardian by default.\n    function isGuardian(address guardian_) external view returns (uint256);\n\n    /// @notice gets user class for `user_`. Class defines which protocols can be paused by guardians.\n    /// Currently there are 2 classes: 0 can be paused by guardians. 1 cannot be paused by guardians.\n    /// New protocols are added as class 0 and will be upgraded to 1 over time.\n    function getUserClass(address user_) external view returns (uint256);\n\n    /// @notice gets exchangePricesAndConfig packed uint256 storage slot for `token_`.\n    function getExchangePricesAndConfig(address token_) external view returns (uint256);\n\n    /// @notice gets rateConfig packed uint256 storage slot for `token_`.\n    function getRateConfig(address token_) external view returns (uint256);\n\n    /// @notice gets totalAmounts packed uint256 storage slot for `token_`.\n    function getTotalAmounts(address token_) external view returns (uint256);\n\n    /// @notice gets userSupply data packed uint256 storage slot for `user_` and `token_`.\n    function getUserSupply(address user_, address token_) external view returns (uint256);\n\n    /// @notice gets userBorrow data packed uint256 storage slot for `user_` and `token_`.\n    function getUserBorrow(address user_, address token_) external view returns (uint256);\n\n    /// @notice returns all `listedTokens_` at the Liquidity contract. Once configured, a token can never be removed.\n    function listedTokens() external view returns (address[] memory listedTokens_);\n\n    /// @notice get the Rate config data `rateData_` for a `token_` compiled from the packed uint256 rateConfig storage slot\n    function getTokenRateData(address token_) external view returns (LiquidityStructs.RateData memory rateData_);\n\n    /// @notice get the Rate config datas `rateDatas_` for multiple `tokens_` compiled from the packed uint256 rateConfig storage slot\n    function getTokensRateData(\n        address[] calldata tokens_\n    ) external view returns (LiquidityStructs.RateData[] memory rateDatas_);\n\n    /// @notice returns general data for `token_` such as rates, exchange prices, utilization, fee, total amounts etc.\n    function getOverallTokenData(\n        address token_\n    ) external view returns (LiquidityStructs.OverallTokenData memory overallTokenData_);\n\n    /// @notice returns general data for multiple `tokens_` such as rates, exchange prices, utilization, fee, total amounts etc.\n    function getOverallTokensData(\n        address[] calldata tokens_\n    ) external view returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);\n\n    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n    function getUserSupplyData(\n        address user_,\n        address token_\n    )\n        external\n        view\n        returns (\n            LiquidityStructs.UserSupplyData memory userSupplyData_,\n            LiquidityStructs.OverallTokenData memory overallTokenData_\n        );\n\n    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n    function getUserMultipleSupplyData(\n        address user_,\n        address[] calldata tokens_\n    )\n        external\n        view\n        returns (\n            LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n            LiquidityStructs.OverallTokenData[] memory overallTokensData_\n        );\n\n    /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n    function getUserBorrowData(\n        address user_,\n        address token_\n    )\n        external\n        view\n        returns (\n            LiquidityStructs.UserBorrowData memory userBorrowData_,\n            LiquidityStructs.OverallTokenData memory overallTokenData_\n        );\n\n    /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n    function getUserMultipleBorrowData(\n        address user_,\n        address[] calldata tokens_\n    )\n        external\n        view\n        returns (\n            LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n            LiquidityStructs.OverallTokenData[] memory overallTokensData_\n        );\n\n    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `supplyTokens_`\n    ///     and returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `borrowTokens_`\n    function getUserMultipleBorrowSupplyData(\n        address user_,\n        address[] calldata supplyTokens_,\n        address[] calldata borrowTokens_\n    )\n        external\n        view\n        returns (\n            LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n            LiquidityStructs.OverallTokenData[] memory overallSupplyTokensData_,\n            LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n            LiquidityStructs.OverallTokenData[] memory overallBorrowTokensData_\n        );\n}\n"
      },
      "contracts/periphery/resolvers/liquidity/structs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Structs as AdminModuleStructs } from \"../../../liquidity/adminModule/structs.sol\";\n\nabstract contract Structs {\n    struct RateData {\n        uint256 version;\n        AdminModuleStructs.RateDataV1Params rateDataV1;\n        AdminModuleStructs.RateDataV2Params rateDataV2;\n    }\n\n    struct OverallTokenData {\n        uint256 borrowRate;\n        uint256 supplyRate;\n        uint256 fee; // revenue fee\n        uint256 lastStoredUtilization;\n        uint256 storageUpdateThreshold;\n        uint256 lastUpdateTimestamp;\n        uint256 supplyExchangePrice;\n        uint256 borrowExchangePrice;\n        uint256 supplyRawInterest;\n        uint256 supplyInterestFree;\n        uint256 borrowRawInterest;\n        uint256 borrowInterestFree;\n        uint256 totalSupply;\n        uint256 totalBorrow;\n        uint256 revenue;\n        RateData rateData;\n    }\n\n    // amounts are always in normal (for withInterest already multiplied with exchange price)\n    struct UserSupplyData {\n        bool modeWithInterest; // true if mode = with interest, false = without interest\n        uint256 supply; // user supply amount\n        // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)\n        uint256 withdrawalLimit;\n        uint256 lastUpdateTimestamp;\n        uint256 expandPercent; // withdrawal limit expand percent in 1e2\n        uint256 expandDuration; // withdrawal limit expand duration in seconds\n        uint256 baseWithdrawalLimit;\n        // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)\n        uint256 withdrawableUntilLimit;\n        uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance\n    }\n\n    // amounts are always in normal (for withInterest already multiplied with exchange price)\n    struct UserBorrowData {\n        bool modeWithInterest; // true if mode = with interest, false = without interest\n        uint256 borrow; // user borrow amount\n        uint256 borrowLimit;\n        uint256 lastUpdateTimestamp;\n        uint256 expandPercent;\n        uint256 expandDuration;\n        uint256 baseBorrowLimit;\n        uint256 maxBorrowLimit;\n        uint256 borrowableUntilLimit;\n        uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance\n    }\n}\n"
      },
      "contracts/reserve/interfaces/iReserveContract.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\n\ninterface IFluidReserveContract {\n    function isRebalancer(address user) external returns (bool);\n\n    function initialize(\n        address[] memory _auths,\n        address[] memory _rebalancers,\n        IFluidLiquidity liquidity_,\n        address owner_\n    ) external;\n\n    function rebalanceFToken(address protocol_) external;\n\n    function rebalanceVault(address protocol_) external;\n\n    function transferFunds(address token_) external;\n\n    function getProtocolTokens(address protocol_) external;\n\n    function updateAuth(address auth_, bool isAuth_) external;\n\n    function updateRebalancer(address rebalancer_, bool isRebalancer_) external;\n\n    function approve(address[] memory protocols_, address[] memory tokens_, uint256[] memory amounts_) external;\n\n    function revoke(address[] memory protocols_, address[] memory tokens_) external;\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 10000000
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}