creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/interfaces/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "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    /// @notice thrown when the calculated borrow rate turns negative. This should never happen.\n    uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;\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 update 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 also be negative for declining rates)\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        int256 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)\n            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n            slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((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) - (slope_ * int256(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            slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\n            if (slope_ < 0) {\n                revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\n            }\n            rate_ = uint256(slope_) / 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 also be negative for declining rates)\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        int256 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)\n            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n            slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((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) - (slope_ * int256(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            slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\n            if (slope_ < 0) {\n                revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\n            }\n            rate_ = uint256(slope_) / 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/common/helpers.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"./variables.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\n\n/// @dev ReentrancyGuard based on OpenZeppelin implementation.\n/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol\nabstract contract ReentrancyGuard is Variables, Error {\n    uint8 internal constant REENTRANCY_NOT_ENTERED = 1;\n    uint8 internal constant REENTRANCY_ENTERED = 2;\n\n    constructor() {\n        // on logic contracts, switch reentrancy to entered so no call is possible (forces delegatecall)\n        _status = REENTRANCY_ENTERED; \n    }\n\n    /// @dev Prevents a contract from calling itself, directly or indirectly.\n    /// See OpenZeppelin implementation for more info\n    modifier reentrancy() {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == REENTRANCY_ENTERED) {\n            revert FluidLiquidityError(ErrorTypes.LiquidityHelpers__Reentrancy);\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = REENTRANCY_ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = REENTRANCY_NOT_ENTERED;\n    }\n}\n\nabstract contract CommonHelpers is ReentrancyGuard {\n    /// @dev Returns the current admin (governance).\n    function _getGovernanceAddr() internal view returns (address governance_) {\n        assembly {\n            governance_ := sload(GOVERNANCE_SLOT)\n        }\n    }\n}\n"
      },
      "contracts/liquidity/common/variables.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract ConstantVariables {\n    /// @dev Storage slot with the admin of the contract. Logic from \"proxy.sol\".\n    /// This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is validated in the constructor.\n    bytes32 internal constant GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n    uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n    /// @dev address that is mapped to the chain native token\n    address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n    /// @dev limit for triggering a revert if sent along excess `msg.value` is bigger than this amount\n    uint256 internal constant NATIVE_AMOUNT_EXCESS_LIMIT = 1e9;\n\n    /// @dev Ignoring leap years\n    uint256 internal constant SECONDS_PER_YEAR = 365 days;\n\n    /// @dev limit any total amount to be half of type(uint128).max (~3.4e38) at type(int128).max (~1.7e38) as safety\n    /// measure for any potential overflows / unexpected outcomes. This is checked for total borrow / supply.\n    uint256 internal constant MAX_TOKEN_AMOUNT_CAP = uint256(uint128(type(int128).max));\n\n    /// @dev time after which a write to storage of exchangePricesAndConfig will happen always.\n    uint256 internal constant FORCE_STORAGE_WRITE_AFTER_TIME = 1 days;\n\n    /// @dev constants used for BigMath conversion from and to storage\n    uint256 internal constant SMALL_COEFFICIENT_SIZE = 10;\n    uint256 internal constant DEFAULT_COEFFICIENT_SIZE = 56;\n    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\n\n    /// @dev constants to increase readability for using bit masks\n    uint256 internal constant FOUR_DECIMALS = 1e4;\n    uint256 internal constant TWELVE_DECIMALS = 1e12;\n    uint256 internal constant X8 = 0xff;\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\ncontract Variables is ConstantVariables {\n    /// @dev address of contract that gets sent the revenue. Configurable by governance\n    address internal _revenueCollector;\n\n    // 12 bytes empty\n\n    // ----- storage slot 1 ------\n\n    /// @dev paused status: status = 1 -> normal. status = 2 -> paused.\n    /// not tightly packed with revenueCollector address to allow for potential changes later that improve gas more\n    /// (revenueCollector is only rarely used by admin methods, where optimization is not as important).\n    /// to be replaced with transient storage once EIP-1153 Transient storage becomes available with dencun upgrade.\n    uint256 internal _status;\n\n    // ----- storage slot 2 ------\n\n    /// @dev 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.\n    /// Governance is auth by default\n    mapping(address => uint256) internal _isAuth;\n\n    // ----- storage slot 3 ------\n\n    /// @dev Guardians can pause lower class users\n    /// Governance can add/remove guardians\n    /// Governance is guardian by default\n    mapping(address => uint256) internal _isGuardian;\n\n    // ----- storage slot 4 ------\n\n    /// @dev 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    mapping(address => uint256) internal _userClass;\n\n    // ----- storage slot 5 ------\n\n    /// @dev exchange prices and token config per token: token -> exchange prices & config\n    /// First 16 bits =>   0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n    /// Next  14 bits =>  16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\n    /// Next  14 bits =>  30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    /// Next  14 bits =>  44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\n    /// Next  33 bits =>  58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591)\n    /// Next  64 bits =>  91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615)\n    /// Next  64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615)\n    /// Next   1 bit  => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree\n    /// Next  14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    /// Next   1 bit  => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree\n    /// Next  14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    /// Last   7 bits => 249-255 => empty for future use\n    ///                             if more free bits are needed in the future, update on storage threshold bits could be reduced to 7 bits\n    ///                             (can plan to add `MAX_TOKEN_CONFIG_UPDATE_THRESHOLD` but need to adjust more bits)\n    ///                             if more bits absolutely needed then we can convert fee, utilization, update on storage threshold,\n    ///                             supplyRatio & borrowRatio from 14 bits to 10bits (1023 max number) where 1000 = 100% & 1 = 0.1%\n    mapping(address => uint256) internal _exchangePricesAndConfig;\n\n    // ----- storage slot 6 ------\n\n    /// @dev Rate related data per token: token -> rate data\n    /// READ (SLOAD): all actions; WRITE (SSTORE): only on set config admin actions\n    /// token => rate related data\n    /// First 4 bits  =>     0-3 => rate version\n    /// rest of the bits are rate dependent:\n\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 => empty for future use\n\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 => empty for future use\n    mapping(address => uint256) internal _rateData;\n\n    // ----- storage slot 7 ------\n\n    /// @dev total supply / borrow amounts for with / without interest per token: token -> amounts\n    /// First  64 bits =>   0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8\n    /// Next   64 bits =>  64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8\n    /// Next   64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8\n    /// Next   64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8\n    mapping(address => uint256) internal _totalAmounts;\n\n    // ----- storage slot 8 ------\n\n    /// @dev user supply data per token: user -> token -> data\n    /// First  1 bit  =>       0 => mode: user supply with or without interest\n    ///                             0 = without, amounts are in normal (i.e. no need to multiply with exchange price)\n    ///                             1 = with interest, amounts are in raw (i.e. must multiply with exchange price to get actual token amounts)\n    /// Next  64 bits =>   1- 64 => user supply amount (normal or raw depends on 1st bit); BigMath: 56 | 8\n    /// Next  64 bits =>  65-128 => previous user withdrawal limit (normal or raw depends on 1st bit); BigMath: 56 | 8\n    /// Next  33 bits => 129-161 => last triggered process timestamp (enough until 16 March 2242 -> max value 8589934591)\n    /// Next  14 bits => 162-175 => expand withdrawal limit percentage (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383).\n    ///                             @dev shrinking is instant\n    /// Next  24 bits => 176-199 => withdrawal limit expand duration in seconds.(Max value 16_777_215; ~4_660 hours, ~194 days)\n    /// Next  18 bits => 200-217 => base withdrawal limit: below this, 100% withdrawals can be done (normal or raw depends on 1st bit); BigMath: 10 | 8\n    /// Next  37 bits => 218-254 => empty for future use\n    /// Last     bit  => 255-255 => is user paused (1 = paused, 0 = not paused)\n    mapping(address => mapping(address => uint256)) internal _userSupplyData;\n\n    // ----- storage slot 9 ------\n\n    /// @dev user borrow data per token: user -> token -> data\n    /// First  1 bit  =>       0 => mode: user borrow with or without interest\n    ///                             0 = without, amounts are in normal (i.e. no need to multiply with exchange price)\n    ///                             1 = with interest, amounts are in raw (i.e. must multiply with exchange price to get actual token amounts)\n    /// Next  64 bits =>   1- 64 => user borrow amount (normal or raw depends on 1st bit); BigMath: 56 | 8\n    /// Next  64 bits =>  65-128 => previous user debt ceiling (normal or raw depends on 1st bit); BigMath: 56 | 8\n    /// Next  33 bits => 129-161 => last triggered process timestamp (enough until 16 March 2242 -> max value 8589934591)\n    /// Next  14 bits => 162-175 => expand debt ceiling percentage (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    ///                             @dev shrinking is instant\n    /// Next  24 bits => 176-199 => debt ceiling expand duration in seconds (Max value 16_777_215; ~4_660 hours, ~194 days)\n    /// Next  18 bits => 200-217 => base debt ceiling: below this, there's no debt ceiling limits (normal or raw depends on 1st bit); BigMath: 10 | 8\n    /// Next  18 bits => 218-235 => max debt ceiling: absolute maximum debt ceiling can expand to (normal or raw depends on 1st bit); BigMath: 10 | 8\n    /// Next  19 bits => 236-254 => empty for future use\n    /// Last     bit  => 255-255 => is user paused (1 = paused, 0 = not paused)\n    mapping(address => mapping(address => uint256)) internal _userBorrowData;\n\n    // ----- storage slot 10 ------\n\n    /// @dev list of allowed tokens at Liquidity. tokens that are once configured can never be completely removed. so this\n    ///      array is append-only.\n    address[] internal _listedTokens;\n}\n"
      },
      "contracts/liquidity/error.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n    error FluidLiquidityError(uint256 errorId_);\n}\n"
      },
      "contracts/liquidity/errorTypes.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n    /***********************************|\n    |         Admin Module              | \n    |__________________________________*/\n\n    /// @notice thrown when an input address is zero\n    uint256 internal constant AdminModule__AddressZero = 10001;\n\n    /// @notice thrown when msg.sender is not governance\n    uint256 internal constant AdminModule__OnlyGovernance = 10002;\n\n    /// @notice thrown when msg.sender is not auth\n    uint256 internal constant AdminModule__OnlyAuths = 10003;\n\n    /// @notice thrown when msg.sender is not guardian\n    uint256 internal constant AdminModule__OnlyGuardians = 10004;\n\n    /// @notice thrown when base withdrawal limit, base debt limit or max withdrawal limit is sent as 0\n    uint256 internal constant AdminModule__LimitZero = 10005;\n\n    /// @notice thrown whenever an invalid input param is given\n    uint256 internal constant AdminModule__InvalidParams = 10006;\n\n    /// @notice thrown if user class 1 is paused (can not be paused)\n    uint256 internal constant AdminModule__UserNotPausable = 10007;\n\n    /// @notice thrown if user is tried to be unpaused but is not paused in the first place\n    uint256 internal constant AdminModule__UserNotPaused = 10008;\n\n    /// @notice thrown if user is not defined yet: Governance didn't yet set any config for this user on a particular token\n    uint256 internal constant AdminModule__UserNotDefined = 10009;\n\n    /// @notice thrown if a token is configured in an invalid order:  1. Set rate config for token 2. Set token config 3. allow any user.\n    uint256 internal constant AdminModule__InvalidConfigOrder = 10010;\n\n    /// @notice thrown if revenue is collected when revenue collector address is not set\n    uint256 internal constant AdminModule__RevenueCollectorNotSet = 10011;\n\n    /// @notice all ValueOverflow errors below are thrown if a certain input param overflows the allowed storage size\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_ZERO = 10012;\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK = 10013;\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_MAX = 10014;\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK1 = 10015;\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK2 = 10016;\n    uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_MAX_V2 = 10017;\n    uint256 internal constant AdminModule__ValueOverflow__FEE = 10018;\n    uint256 internal constant AdminModule__ValueOverflow__THRESHOLD = 10019;\n    uint256 internal constant AdminModule__ValueOverflow__EXPAND_PERCENT = 10020;\n    uint256 internal constant AdminModule__ValueOverflow__EXPAND_DURATION = 10021;\n    uint256 internal constant AdminModule__ValueOverflow__EXPAND_PERCENT_BORROW = 10022;\n    uint256 internal constant AdminModule__ValueOverflow__EXPAND_DURATION_BORROW = 10023;\n    uint256 internal constant AdminModule__ValueOverflow__EXCHANGE_PRICES = 10024;\n    uint256 internal constant AdminModule__ValueOverflow__UTILIZATION = 10025;\n\n    /// @notice thrown when an address is not a contract\n    uint256 internal constant AdminModule__AddressNotAContract = 10026;\n\n    /***********************************|\n    |          User Module              | \n    |__________________________________*/\n\n    /// @notice thrown when user operations are paused for an interacted token\n    uint256 internal constant UserModule__UserNotDefined = 11001;\n\n    /// @notice thrown when user operations are paused for an interacted token\n    uint256 internal constant UserModule__UserPaused = 11002;\n\n    /// @notice thrown when user's try to withdraw below withdrawal limit\n    uint256 internal constant UserModule__WithdrawalLimitReached = 11003;\n\n    /// @notice thrown when user's try to borrow above borrow limit\n    uint256 internal constant UserModule__BorrowLimitReached = 11004;\n\n    /// @notice thrown when user sent supply/withdraw and borrow/payback both as 0\n    uint256 internal constant UserModule__OperateAmountsZero = 11005;\n\n    /// @notice thrown when user sent supply/withdraw or borrow/payback both as bigger than 2**128\n    uint256 internal constant UserModule__OperateAmountOutOfBounds = 11006;\n\n    /// @notice thrown when the operate amount for supply / withdraw / borrow / payback is below the minimum amount\n    /// that would cause a storage difference after BigMath & rounding imprecision. Extremely unlikely to ever happen\n    /// for all normal use-cases.\n    uint256 internal constant UserModule__OperateAmountInsufficient = 11007;\n\n    /// @notice thrown when withdraw or borrow is executed but withdrawTo or borrowTo is the zero address\n    uint256 internal constant UserModule__ReceiverNotDefined = 11008;\n\n    /// @notice thrown when user did send excess or insufficient amount (beyond rounding issues)\n    uint256 internal constant UserModule__TransferAmountOutOfBounds = 11009;\n\n    /// @notice thrown when user sent msg.value along for an operation not for the native token\n    uint256 internal constant UserModule__MsgValueForNonNativeToken = 11010;\n\n    /// @notice thrown when a borrow operation is done when utilization is above 100%\n    uint256 internal constant UserModule__MaxUtilizationReached = 11011;\n\n    /// @notice all ValueOverflow errors below are thrown if a certain input param or calc result overflows the allowed storage size\n    uint256 internal constant UserModule__ValueOverflow__EXCHANGE_PRICES = 11012;\n    uint256 internal constant UserModule__ValueOverflow__UTILIZATION = 11013;\n    uint256 internal constant UserModule__ValueOverflow__TOTAL_SUPPLY = 11014;\n    uint256 internal constant UserModule__ValueOverflow__TOTAL_BORROW = 11015;\n\n    /***********************************|\n    |         LiquidityHelpers          | \n    |__________________________________*/\n\n    /// @notice thrown when a reentrancy happens\n    uint256 internal constant LiquidityHelpers__Reentrancy = 12001;\n}\n"
      },
      "contracts/liquidity/userModule/events.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Events {\n    /// @notice emitted on any `operate()` execution: deposit / supply / withdraw / borrow.\n    /// includes info related to the executed operation, new total amounts (packed uint256 of BigMath numbers as in storage)\n    /// and exchange prices (packed uint256 as in storage).\n    /// @param user protocol that triggered this operation (e.g. via an fToken or via Vault protocol)\n    /// @param token token address for which this operation was executed\n    /// @param supplyAmount supply amount for the operation. if >0 then a deposit happened, if <0 then a withdrawal happened.\n    ///                     if 0 then nothing.\n    /// @param borrowAmount borrow amount for the operation. if >0 then a borrow happened, if <0 then a payback happened.\n    ///                     if 0 then nothing.\n    /// @param withdrawTo   address that funds where withdrawn to (if supplyAmount <0)\n    /// @param borrowTo     address that funds where borrowed to (if borrowAmount >0)\n    /// @param totalAmounts updated total amounts, stacked uint256 as written to storage:\n    /// First  64 bits =>   0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8\n    /// Next   64 bits =>  64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8\n    /// Next   64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8\n    /// Next   64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8\n    /// @param exchangePricesAndConfig updated exchange prices and configs storage slot. Contains updated supply & borrow exchange price:\n    /// First 16 bits =>   0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n    /// Next  14 bits =>  16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\n    /// Next  14 bits =>  30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    /// Next  14 bits =>  44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\n    /// Next  33 bits =>  58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591)\n    /// Next  64 bits =>  91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615)\n    /// Next  64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615)\n    /// Next   1 bit  => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree\n    /// Next  14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    /// Next   1 bit  => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree\n    /// Next  14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n    event LogOperate(\n        address indexed user,\n        address indexed token,\n        int256 supplyAmount,\n        int256 borrowAmount,\n        address withdrawTo,\n        address borrowTo,\n        uint256 totalAmounts,\n        uint256 exchangePricesAndConfig\n    );\n}\n"
      },
      "contracts/liquidity/userModule/main.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { FixedPointMathLib } from \"solmate/src/utils/FixedPointMathLib.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { BigMathMinified } from \"../../libraries/bigMathMinified.sol\";\nimport { LiquidityCalcs } from \"../../libraries/liquidityCalcs.sol\";\nimport { LiquiditySlotsLink } from \"../../libraries/liquiditySlotsLink.sol\";\nimport { CommonHelpers } from \"../common/helpers.sol\";\nimport { Events } from \"./events.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\n\ninterface IProtocol {\n    function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external;\n}\n\nabstract contract CoreInternals is Error, CommonHelpers, Events {\n    using BigMathMinified for uint256;\n\n    /// @dev supply or withdraw for both with interest & interest free.\n    /// positive `amount_` is deposit, negative `amount_` is withdraw.\n    function _supplyOrWithdraw(\n        address token_,\n        int256 amount_,\n        uint256 supplyExchangePrice_\n    ) internal returns (int256 newSupplyInterestRaw_, int256 newSupplyInterestFree_) {\n        uint256 userSupplyData_ = _userSupplyData[msg.sender][token_];\n\n        if (userSupplyData_ == 0) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__UserNotDefined);\n        }\n        if ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_IS_PAUSED) & 1 == 1) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__UserPaused);\n        }\n\n        // extract user supply amount\n        uint256 userSupply_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\n        userSupply_ = (userSupply_ >> DEFAULT_EXPONENT_SIZE) << (userSupply_ & DEFAULT_EXPONENT_MASK);\n\n        // calculate current, updated (expanded etc.) withdrawal limit\n        uint256 newWithdrawalLimit_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(userSupplyData_, userSupply_);\n\n        // calculate updated user supply amount\n        if (userSupplyData_ & 1 == 1) {\n            // mode: with interest\n            if (amount_ > 0) {\n                // convert amount from normal to raw (divide by exchange price) -> round down for deposit\n                newSupplyInterestRaw_ = (amount_ * int256(EXCHANGE_PRICES_PRECISION)) / int256(supplyExchangePrice_);\n                userSupply_ = userSupply_ + uint256(newSupplyInterestRaw_);\n            } else {\n                // convert amount from normal to raw (divide by exchange price) -> round up for withdraw\n                newSupplyInterestRaw_ = -int256(\n                    FixedPointMathLib.mulDivUp(uint256(-amount_), EXCHANGE_PRICES_PRECISION, supplyExchangePrice_)\n                );\n                // if withdrawal is more than user's supply then solidity will throw here\n                userSupply_ = userSupply_ - uint256(-newSupplyInterestRaw_);\n            }\n        } else {\n            // mode: without interest\n            newSupplyInterestFree_ = amount_;\n            if (newSupplyInterestFree_ > 0) {\n                userSupply_ = userSupply_ + uint256(newSupplyInterestFree_);\n            } else {\n                // if withdrawal is more than user's supply then solidity will throw here\n                userSupply_ = userSupply_ - uint256(-newSupplyInterestFree_);\n            }\n        }\n\n        if (amount_ < 0 && userSupply_ < newWithdrawalLimit_) {\n            // if withdraw, then check the user supply after withdrawal is above withdrawal limit\n            revert FluidLiquidityError(ErrorTypes.UserModule__WithdrawalLimitReached);\n        }\n\n        // calculate withdrawal limit to store as previous withdrawal limit in storage\n        newWithdrawalLimit_ = LiquidityCalcs.calcWithdrawalLimitAfterOperate(\n            userSupplyData_,\n            userSupply_,\n            newWithdrawalLimit_\n        );\n\n        // Converting user's supply into BigNumber\n        userSupply_ = userSupply_.toBigNumber(\n            DEFAULT_COEFFICIENT_SIZE,\n            DEFAULT_EXPONENT_SIZE,\n            BigMathMinified.ROUND_DOWN\n        );\n        if (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64) == userSupply_) {\n            // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\n            // is present then rounding will be in the right direction to avoid any potential manipulation.\n            revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\n        }\n\n        // Converting withdrawal limit into BigNumber\n        newWithdrawalLimit_ = newWithdrawalLimit_.toBigNumber(\n            DEFAULT_COEFFICIENT_SIZE,\n            DEFAULT_EXPONENT_SIZE,\n            BigMathMinified.ROUND_DOWN\n        );\n\n        // Updating on storage\n        _userSupplyData[msg.sender][token_] =\n            // mask to update bits 1-161 (supply amount, withdrawal limit, timestamp)\n            (userSupplyData_ & 0xfffffffffffffffffffffffc0000000000000000000000000000000000000001) |\n            (userSupply_ << LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) | // converted to BigNumber can not overflow\n            (newWithdrawalLimit_ << LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) | // converted to BigNumber can not overflow\n            (block.timestamp << LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP);\n    }\n\n    /// @dev borrow or payback for both with interest & interest free.\n    /// positive `amount_` is borrow, negative `amount_` is payback.\n    function _borrowOrPayback(\n        address token_,\n        int256 amount_,\n        uint256 borrowExchangePrice_\n    ) internal returns (int256 newBorrowInterestRaw_, int256 newBorrowInterestFree_) {\n        uint256 userBorrowData_ = _userBorrowData[msg.sender][token_];\n\n        if (userBorrowData_ == 0) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__UserNotDefined);\n        }\n        if ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_IS_PAUSED) & 1 == 1) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__UserPaused);\n        }\n\n        // extract user borrow amount\n        uint256 userBorrow_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\n        userBorrow_ = (userBorrow_ >> DEFAULT_EXPONENT_SIZE) << (userBorrow_ & DEFAULT_EXPONENT_MASK);\n\n        // calculate current, updated (expanded etc.) borrow limit\n        uint256 newBorrowLimit_ = LiquidityCalcs.calcBorrowLimitBeforeOperate(userBorrowData_, userBorrow_);\n\n        // calculate updated user borrow amount\n        if (userBorrowData_ & 1 == 1) {\n            // with interest\n            if (amount_ > 0) {\n                // convert amount normal to raw (divide by exchange price) -> round up for borrow\n                newBorrowInterestRaw_ = int256(\n                    FixedPointMathLib.mulDivUp(uint256(amount_), EXCHANGE_PRICES_PRECISION, borrowExchangePrice_)\n                );\n                userBorrow_ = userBorrow_ + uint256(newBorrowInterestRaw_);\n            } else {\n                // convert amount from normal to raw (divide by exchange price) -> round down for payback\n                newBorrowInterestRaw_ = (amount_ * int256(EXCHANGE_PRICES_PRECISION)) / int256(borrowExchangePrice_);\n                userBorrow_ = userBorrow_ - uint256(-newBorrowInterestRaw_);\n            }\n        } else {\n            // without interest\n            newBorrowInterestFree_ = amount_;\n            if (newBorrowInterestFree_ > 0) {\n                // borrowing\n                userBorrow_ = userBorrow_ + uint256(newBorrowInterestFree_);\n            } else {\n                // payback\n                userBorrow_ = userBorrow_ - uint256(-newBorrowInterestFree_);\n            }\n        }\n\n        if (amount_ > 0 && userBorrow_ > newBorrowLimit_) {\n            // if borrow, then check the user borrow amount after borrowing is below borrow limit\n            revert FluidLiquidityError(ErrorTypes.UserModule__BorrowLimitReached);\n        }\n\n        // calculate borrow limit to store as previous borrow limit in storage\n        newBorrowLimit_ = LiquidityCalcs.calcBorrowLimitAfterOperate(userBorrowData_, userBorrow_, newBorrowLimit_);\n\n        // Converting user's borrowings into bignumber\n        userBorrow_ = userBorrow_.toBigNumber(\n            DEFAULT_COEFFICIENT_SIZE,\n            DEFAULT_EXPONENT_SIZE,\n            BigMathMinified.ROUND_UP\n        );\n\n        if (((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64) == userBorrow_) {\n            // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\n            // is present then rounding will be in the right direction to avoid any potential manipulation.\n            revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\n        }\n\n        // Converting borrow limit into bignumber\n        newBorrowLimit_ = newBorrowLimit_.toBigNumber(\n            DEFAULT_COEFFICIENT_SIZE,\n            DEFAULT_EXPONENT_SIZE,\n            BigMathMinified.ROUND_DOWN\n        );\n\n        // Updating on storage\n        _userBorrowData[msg.sender][token_] =\n            // mask to update bits 1-161 (borrow amount, borrow limit, timestamp)\n            (userBorrowData_ & 0xfffffffffffffffffffffffc0000000000000000000000000000000000000001) |\n            (userBorrow_ << LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) | // converted to BigNumber can not overflow\n            (newBorrowLimit_ << LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) | // converted to BigNumber can not overflow\n            (block.timestamp << LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP);\n    }\n\n    /// @dev checks if `supplyAmount_` & borrowAmount amounts balance themselves out (checked before calling this method):\n    /// -   supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\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 _isInOutBalancedOut(\n        int256 supplyAmount_,\n        address withdrawTo_,\n        address borrowTo_,\n        bytes memory callbackData_\n    ) internal view returns (bool) {\n        if (callbackData_.length < 20) {\n            return false;\n        }\n\n        address inFrom_;\n        assembly {\n            inFrom_ := mload(\n                add(\n                    // add padding for length as present for dynamic arrays in memory\n                    add(callbackData_, 32),\n                    // assembly expects address with leading zeros / left padded so need to use 32 as length here\n                    sub(mload(callbackData_), 32)\n                )\n            )\n        }\n        return\n            // case: supply & borrow. borrow receiver must be the same as depositor and must be protocol\n            (supplyAmount_ > 0 && inFrom_ == borrowTo_ && inFrom_ == msg.sender) ||\n            // case: withdraw & payback. withdraw receiver must be the same as depositor and must be protocol\n            (supplyAmount_ < 0 && inFrom_ == withdrawTo_ && inFrom_ == msg.sender);\n    }\n}\n\ninterface IZtakingPool {\n    ///@notice Stake a specified amount of a particular supported token into the Ztaking Pool\n    ///@param _token The token to deposit/stake in the Ztaking Pool\n    ///@param _for The user to deposit/stake on behalf of\n    ///@param _amount The amount of token to deposit/stake into the Ztaking Pool\n    function depositFor(address _token, address _for, uint256 _amount) external;\n\n    ///@notice Withdraw a specified amount of a particular supported token previously staked into the Ztaking Pool\n    ///@param _token The token to withdraw from the Ztaking Pool\n    ///@param _amount The amount of token to withdraw from the Ztaking Pool\n    function withdraw(address _token, uint256 _amount) external;\n}\n\n/// @title  Fluid Liquidity UserModule\n/// @notice Fluid Liquidity public facing endpoint logic contract that implements the `operate()` method.\n///         operate can be used to deposit, withdraw, borrow & payback funds, given that they have the necessary\n///         user config allowance. Interacting users must be allowed via the Fluid Liquidity AdminModule first.\n///         Intended users are thus allow-listed protocols, e.g. the Lending protocol (fTokens), Vault protocol etc.\n/// @dev For view methods / accessing data, use the \"LiquidityResolver\" periphery contract.\ncontract FluidLiquidityUserModule is CoreInternals {\n    using SafeERC20 for IERC20;\n    using BigMathMinified for uint256;\n\n    address private constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;\n    IZtakingPool private constant ZIRCUIT = IZtakingPool(0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6);\n\n    /// @dev struct for vars used in operate() that would otherwise cause a Stack too deep error\n    struct OperateMemoryVars {\n        bool skipTransfers;\n        uint256 supplyExchangePrice;\n        uint256 borrowExchangePrice;\n        uint256 supplyRawInterest;\n        uint256 supplyInterestFree;\n        uint256 borrowRawInterest;\n        uint256 borrowInterestFree;\n        uint256 totalAmounts;\n        uint256 exchangePricesAndConfig;\n    }\n\n    /// @notice inheritdoc IFluidLiquidity\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 reentrancy returns (uint256 memVar3_, uint256 memVar4_) {\n        if (supplyAmount_ == 0 && borrowAmount_ == 0) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountsZero);\n        }\n        if (\n            supplyAmount_ < type(int128).min ||\n            supplyAmount_ > type(int128).max ||\n            borrowAmount_ < type(int128).min ||\n            borrowAmount_ > type(int128).max\n        ) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountOutOfBounds);\n        }\n        if ((supplyAmount_ < 0 && withdrawTo_ == address(0)) || (borrowAmount_ > 0 && borrowTo_ == address(0))) {\n            revert FluidLiquidityError(ErrorTypes.UserModule__ReceiverNotDefined);\n        }\n        if (token_ != NATIVE_TOKEN_ADDRESS && msg.value > 0) {\n            // revert: there should not be msg.value if the token is not the native token\n            revert FluidLiquidityError(ErrorTypes.UserModule__MsgValueForNonNativeToken);\n        }\n\n        OperateMemoryVars memory o_;\n\n        // @dev temporary memory variables used as helper in between to avoid assigning new memory variables\n        uint256 memVar_;\n        // memVar2_ => operateAmountIn: deposit + payback\n        uint256 memVar2_ = uint256((supplyAmount_ > 0 ? supplyAmount_ : int256(0))) +\n            uint256((borrowAmount_ < 0 ? -borrowAmount_ : int256(0)));\n        // check if in & output amounts balance themselves out:\n        // supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\n        // AND msg.value must be 0 otherwise we assume protocol wants normal transfers to happen\n        if (\n            supplyAmount_ == borrowAmount_ &&\n            msg.value == 0 &&\n            _isInOutBalancedOut(supplyAmount_, withdrawTo_, borrowTo_, callbackData_)\n        ) {\n            memVar2_ = 0; // set to 0 to skip transfers IN\n            o_.skipTransfers = true; // set flag to true to skip transfers OUT\n        }\n        if (token_ == NATIVE_TOKEN_ADDRESS) {\n            unchecked {\n                // check supply and payback amount is covered by available sent msg.value and\n                // protection that msg.value is not unintentionally way more than actually used in operate()\n                if (memVar2_ > msg.value || msg.value > memVar2_ + NATIVE_AMOUNT_EXCESS_LIMIT) {\n                    revert FluidLiquidityError(ErrorTypes.UserModule__TransferAmountOutOfBounds);\n                }\n            }\n            memVar2_ = 0; // set to 0 to skip transfers IN more gas efficient. No need for native token.\n        }\n        // if supply or payback or both -> transfer token amount from sender to here.\n        // for native token this is already covered by msg.value checks in operate(). memVar2_ is set to 0\n        // for same amounts in same operate(): supply(+) == borrow(+), withdraw(-) == payback(-). memVar2_ is set to 0\n        if (memVar2_ > 0) {\n            // memVar_ => initial token balance of this contract\n            memVar_ = IERC20(token_).balanceOf(address(this));\n            // trigger protocol to send token amount and pass callback data\n            IProtocol(msg.sender).liquidityCallback(token_, memVar2_, callbackData_);\n            // memVar_ => current token balance of this contract - initial balance\n            memVar_ = IERC20(token_).balanceOf(address(this)) - memVar_;\n            unchecked {\n                if (memVar_ < memVar2_ || memVar_ > (memVar2_ + 10)) {\n                    // revert if protocol did not send enough to cover supply / payback\n                    // or if protocol sent more than expected, with minor tolerance for any potential rounding issues,\n                    // even though that should not be needed (liquidityCallback should send exact amount as in params).\n                    revert FluidLiquidityError(ErrorTypes.UserModule__TransferAmountOutOfBounds);\n                }\n            }\n\n            // ---------- temporary code start -----------------------\n            // temporary addition for weETH: if token is weETH -> deposit to Zircuit\n            if ((token_ == WEETH) && (IERC20(WEETH).allowance(address(this), address(ZIRCUIT)) > 0)) {\n                ZIRCUIT.depositFor(WEETH, address(this), memVar_);\n            }\n            // temporary code also includes: WEETH & ZIRCUIT constant, IZtakingPool interface\n            // ---------- temporary code end -----------------------\n        }\n\n        o_.exchangePricesAndConfig = _exchangePricesAndConfig[token_];\n\n        // calculate updated exchange prices\n        (o_.supplyExchangePrice, o_.borrowExchangePrice) = LiquidityCalcs.calcExchangePrices(\n            o_.exchangePricesAndConfig\n        );\n\n        // Extract total supply / borrow amounts for the token\n        o_.totalAmounts = _totalAmounts[token_];\n        memVar_ = o_.totalAmounts & X64;\n        o_.supplyRawInterest = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\n        memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n        o_.supplyInterestFree = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\n        memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n        o_.borrowRawInterest = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\n        // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n        memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n        o_.borrowInterestFree = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\n\n        if (supplyAmount_ != 0) {\n            // execute supply or withdraw and update total amounts\n            {\n                uint256 totalAmountsBefore_ = o_.totalAmounts;\n                (int256 newSupplyInterestRaw_, int256 newSupplyInterestFree_) = _supplyOrWithdraw(\n                    token_,\n                    supplyAmount_,\n                    o_.supplyExchangePrice\n                );\n                // update total amounts. this is done here so that values are only written to storage once\n                // if a borrow / payback also happens in the same `operate()` call\n                if (newSupplyInterestFree_ == 0) {\n                    // Note newSupplyInterestFree_ can ONLY be 0 if mode is with interest,\n                    // easy to check as that variable is NOT the result of a dvision etc.\n                    // supply or withdraw with interest -> raw amount\n                    if (newSupplyInterestRaw_ > 0) {\n                        o_.supplyRawInterest += uint256(newSupplyInterestRaw_);\n                    } else {\n                        unchecked {\n                            o_.supplyRawInterest = o_.supplyRawInterest > uint256(-newSupplyInterestRaw_)\n                                ? o_.supplyRawInterest - uint256(-newSupplyInterestRaw_)\n                                : 0; // withdraw amount is > total supply -> withdraw total supply down to 0\n                            // Note no risk here as if the user withdraws more than supplied it would revert already\n                            // earlier. Total amounts can end up < sum of user amounts because of rounding\n                        }\n                    }\n\n                    // Note check for revert {UserModule}__ValueOverflow__TOTAL_SUPPLY is further down when we anyway\n                    // calculate the normal amount from raw\n\n                    // Converting the updated total amount into big number for storage\n                    memVar_ = o_.supplyRawInterest.toBigNumber(\n                        DEFAULT_COEFFICIENT_SIZE,\n                        DEFAULT_EXPONENT_SIZE,\n                        BigMathMinified.ROUND_DOWN\n                    );\n                    // update total supply with interest at total amounts in storage (only update changed values)\n                    o_.totalAmounts =\n                        // mask to update bits 0-63\n                        (o_.totalAmounts & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000) |\n                        memVar_; // converted to BigNumber can not overflow\n                } else {\n                    // supply or withdraw interest free -> normal amount\n                    if (newSupplyInterestFree_ > 0) {\n                        o_.supplyInterestFree += uint256(newSupplyInterestFree_);\n                    } else {\n                        unchecked {\n                            o_.supplyInterestFree = o_.supplyInterestFree > uint256(-newSupplyInterestFree_)\n                                ? o_.supplyInterestFree - uint256(-newSupplyInterestFree_)\n                                : 0; // withdraw amount is > total supply -> withdraw total supply down to 0\n                            // Note no risk here as if the user withdraws more than supplied it would revert already\n                            // earlier. Total amounts can end up < sum of user amounts because of rounding\n                        }\n                    }\n                    if (o_.supplyInterestFree > MAX_TOKEN_AMOUNT_CAP) {\n                        // only withdrawals allowed if total supply interest free reaches MAX_TOKEN_AMOUNT_CAP\n                        revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_SUPPLY);\n                    }\n                    // Converting the updated total amount into big number for storage\n                    memVar_ = o_.supplyInterestFree.toBigNumber(\n                        DEFAULT_COEFFICIENT_SIZE,\n                        DEFAULT_EXPONENT_SIZE,\n                        BigMathMinified.ROUND_DOWN\n                    );\n                    // update total supply interest free at total amounts in storage (only update changed values)\n                    o_.totalAmounts =\n                        // mask to update bits 64-127\n                        (o_.totalAmounts & 0xffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff) |\n                        (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE); // converted to BigNumber can not overflow\n                }\n                if (totalAmountsBefore_ == o_.totalAmounts) {\n                    // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\n                    // is present then rounding will be in the right direction to avoid any potential manipulation.\n                    revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\n                }\n            }\n        }\n        if (borrowAmount_ != 0) {\n            // execute borrow or payback and update total amounts\n            {\n                uint256 totalAmountsBefore_ = o_.totalAmounts;\n                (int256 newBorrowInterestRaw_, int256 newBorrowInterestFree_) = _borrowOrPayback(\n                    token_,\n                    borrowAmount_,\n                    o_.borrowExchangePrice\n                );\n                // update total amounts. this is done here so that values are only written to storage once\n                // if a supply / withdraw also happens in the same `operate()` call\n                if (newBorrowInterestFree_ == 0) {\n                    // Note newBorrowInterestFree_ can ONLY be 0 if mode is with interest,\n                    // easy to check as that variable is NOT the result of a dvision etc.\n                    // borrow or payback with interest -> raw amount\n                    if (newBorrowInterestRaw_ > 0) {\n                        o_.borrowRawInterest += uint256(newBorrowInterestRaw_);\n                    } else {\n                        unchecked {\n                            o_.borrowRawInterest = o_.borrowRawInterest > uint256(-newBorrowInterestRaw_)\n                                ? o_.borrowRawInterest - uint256(-newBorrowInterestRaw_)\n                                : 0; // payback amount is > total borrow -> payback total borrow down to 0\n                        }\n                    }\n\n                    // Note check for revert UserModule__ValueOverflow__TOTAL_BORROW is further down when we anyway\n                    // calculate the normal amount from raw\n\n                    // Converting the updated total amount into big number for storage\n                    memVar_ = o_.borrowRawInterest.toBigNumber(\n                        DEFAULT_COEFFICIENT_SIZE,\n                        DEFAULT_EXPONENT_SIZE,\n                        BigMathMinified.ROUND_UP\n                    );\n                    // update total borrow with interest at total amounts in storage (only update changed values)\n                    o_.totalAmounts =\n                        // mask to update bits 128-191\n                        (o_.totalAmounts & 0xffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff) |\n                        (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST); // converted to BigNumber can not overflow\n                } else {\n                    // borrow or payback interest free -> normal amount\n                    if (newBorrowInterestFree_ > 0) {\n                        o_.borrowInterestFree += uint256(newBorrowInterestFree_);\n                    } else {\n                        unchecked {\n                            o_.borrowInterestFree = o_.borrowInterestFree > uint256(-newBorrowInterestFree_)\n                                ? o_.borrowInterestFree - uint256(-newBorrowInterestFree_)\n                                : 0; // payback amount is > total borrow -> payback total borrow down to 0\n                        }\n                    }\n                    if (o_.borrowInterestFree > MAX_TOKEN_AMOUNT_CAP) {\n                        // only payback allowed if total borrow interest free reaches MAX_TOKEN_AMOUNT_CAP\n                        revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_BORROW);\n                    }\n                    // Converting the updated total amount into big number for storage\n                    memVar_ = o_.borrowInterestFree.toBigNumber(\n                        DEFAULT_COEFFICIENT_SIZE,\n                        DEFAULT_EXPONENT_SIZE,\n                        BigMathMinified.ROUND_UP\n                    );\n                    // update total borrow interest free at total amounts in storage (only update changed values)\n                    o_.totalAmounts =\n                        // mask to update bits 192-255\n                        (o_.totalAmounts & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff) |\n                        (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE); // converted to BigNumber can not overflow\n                }\n                if (totalAmountsBefore_ == o_.totalAmounts) {\n                    // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\n                    // is present then rounding will be in the right direction to avoid any potential manipulation.\n                    revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\n                }\n            }\n        }\n        // Updating total amounts on storage\n        _totalAmounts[token_] = o_.totalAmounts;\n        {\n            // update exchange prices / utilization / ratios\n            // exchangePricesAndConfig is only written to storage if either utilization, supplyRatio or borrowRatio\n            // change is above the required storageUpdateThreshold config value or if the last write was > 1 day ago.\n\n            // 1. calculate new supply ratio, borrow ratio & utilization.\n            // 2. check if last storage write was > 1 day ago.\n            // 3. If false -> check if utilization is above update threshold\n            // 4. If false -> check if supply ratio is above update threshold\n            // 5. If false -> check if borrow ratio is above update threshold\n            // 6. If any true, then update on storage\n\n            // ########## calculating supply ratio ##########\n            // supplyWithInterest in normal amount\n            memVar3_ = ((o_.supplyRawInterest * o_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION);\n            if (memVar3_ > MAX_TOKEN_AMOUNT_CAP && supplyAmount_ > 0) {\n                // only withdrawals allowed if total supply raw reaches MAX_TOKEN_AMOUNT_CAP\n                revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_SUPPLY);\n            }\n            // memVar_ => total supply. set here so supplyWithInterest (memVar3_) is only calculated once. For utilization\n            memVar_ = o_.supplyInterestFree + memVar3_;\n            if (memVar3_ > o_.supplyInterestFree) {\n                // memVar3_ is ratio with 1 bit as 0 as supply interest raw is bigger\n                memVar3_ = ((o_.supplyInterestFree * FOUR_DECIMALS) / memVar3_) << 1;\n                // because of checking to divide by bigger amount, ratio can never be > 100%\n            } else if (memVar3_ < o_.supplyInterestFree) {\n                // memVar3_ is ratio with 1 bit as 1 as supply interest free is bigger\n                memVar3_ = (((memVar3_ * FOUR_DECIMALS) / o_.supplyInterestFree) << 1) | 1;\n                // because of checking to divide by bigger amount, ratio can never be > 100%\n            } else if (memVar_ > 0) {\n                // supplies match exactly (memVar3_  == o_.supplyInterestFree) and total supplies are not 0\n                // -> set ratio to 1 (with first bit set to 0, doesn't matter)\n                memVar3_ = FOUR_DECIMALS << 1;\n            } // else if total supply = 0, memVar3_ (supplyRatio) is already 0.\n\n            // ########## calculating borrow ratio ##########\n            // borrowWithInterest in normal amount\n            memVar4_ = ((o_.borrowRawInterest * o_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION);\n            if (memVar4_ > MAX_TOKEN_AMOUNT_CAP && borrowAmount_ > 0) {\n                // only payback allowed if total borrow raw reaches MAX_TOKEN_AMOUNT_CAP\n                revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_BORROW);\n            }\n            // memVar2_ => total borrow. set here so borrowWithInterest (memVar4_) is only calculated once. For utilization\n            memVar2_ = o_.borrowInterestFree + memVar4_;\n            if (memVar4_ > o_.borrowInterestFree) {\n                // memVar4_ is ratio with 1 bit as 0 as borrow interest raw is bigger\n                memVar4_ = ((o_.borrowInterestFree * FOUR_DECIMALS) / memVar4_) << 1;\n                // because of checking to divide by bigger amount, ratio can never be > 100%\n            } else if (memVar4_ < o_.borrowInterestFree) {\n                // memVar4_ is ratio with 1 bit as 1 as borrow interest free is bigger\n                memVar4_ = (((memVar4_ * FOUR_DECIMALS) / o_.borrowInterestFree) << 1) | 1;\n                // because of checking to divide by bigger amount, ratio can never be > 100%\n            } else if (memVar2_ > 0) {\n                // borrows match exactly (memVar4_  == o_.borrowInterestFree) and total borrows are not 0\n                // -> set ratio to 1 (with first bit set to 0, doesn't matter)\n                memVar4_ = FOUR_DECIMALS << 1;\n            } // else if total borrow = 0, memVar4_ (borrowRatio) is already 0.\n\n            // calculate utilization. If there is no supply, utilization must be 0 (avoid division by 0)\n            uint256 utilization_;\n            if (memVar_ > 0) {\n                utilization_ = ((memVar2_ * FOUR_DECIMALS) / memVar_);\n                if (utilization_ > FOUR_DECIMALS && borrowAmount_ > 0) {\n                    // revert on new borrows when utilization is above 100%\n                    revert FluidLiquidityError(ErrorTypes.UserModule__MaxUtilizationReached);\n                }\n            }\n\n            // check if time difference is big enough (> 1 day)\n            unchecked {\n                if (\n                    block.timestamp >\n                    // extract last update timestamp + 1 day\n                    (((o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33) +\n                        FORCE_STORAGE_WRITE_AFTER_TIME)\n                ) {\n                    memVar_ = 1; // set write to storage flag\n                } else {\n                    memVar_ = 0;\n                }\n            }\n\n            if (memVar_ == 0) {\n                // time difference is not big enough to cause storage write -> check utilization\n\n                // memVar_ => extract last utilization\n                memVar_ = (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14;\n                // memVar2_ => storage update threshold in percent\n                memVar2_ =\n                    (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD) &\n                    X14;\n                unchecked {\n                    // set memVar_ to 1 if current utilization to previous utilization difference is > update storage threshold\n                    memVar_ = (utilization_ > memVar_ ? utilization_ - memVar_ : memVar_ - utilization_) > memVar2_\n                        ? 1\n                        : 0;\n                    if (memVar_ == 0) {\n                        // utilization & time difference is not big enough -> check supplyRatio difference\n                        // memVar_ => extract last supplyRatio\n                        memVar_ =\n                            (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) &\n                            X15;\n                        // set memVar_ to 1 if current supplyRatio to previous supplyRatio difference is > update storage threshold\n                        if ((memVar_ & 1) == (memVar3_ & 1)) {\n                            memVar_ = memVar_ >> 1;\n                            memVar_ = (\n                                (memVar3_ >> 1) > memVar_ ? (memVar3_ >> 1) - memVar_ : memVar_ - (memVar3_ >> 1)\n                            ) > memVar2_\n                                ? 1\n                                : 0; // memVar3_ = supplyRatio, memVar_ = previous supplyRatio, memVar2_ = update storage threshold\n                        } else {\n                            // if inverse bit is changing then always update on storage\n                            memVar_ = 1;\n                        }\n                        if (memVar_ == 0) {\n                            // utilization, time, and supplyRatio difference is not big enough -> check borrowRatio difference\n                            // memVar_ => extract last borrowRatio\n                            memVar_ =\n                                (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\n                                X15;\n                            // set memVar_ to 1 if current borrowRatio to previous borrowRatio difference is > update storage threshold\n                            if ((memVar_ & 1) == (memVar4_ & 1)) {\n                                memVar_ = memVar_ >> 1;\n                                memVar_ = (\n                                    (memVar4_ >> 1) > memVar_ ? (memVar4_ >> 1) - memVar_ : memVar_ - (memVar4_ >> 1)\n                                ) > memVar2_\n                                    ? 1\n                                    : 0; // memVar4_ = borrowRatio, memVar_ = previous borrowRatio, memVar2_ = update storage threshold\n                            } else {\n                                // if inverse bit is changing then always update on storage\n                                memVar_ = 1;\n                            }\n                        }\n                    }\n                }\n            }\n\n            // memVar_ is 1 if either time diff was enough or if\n            // utilization, supplyRatio or borrowRatio difference was > update storage threshold\n            if (memVar_ == 1) {\n                // memVar_ => calculate new borrow rate for utilization. includes value overflow check.\n                memVar_ = LiquidityCalcs.calcBorrowRateFromUtilization(_rateData[token_], utilization_);\n                // ensure values written to storage do not exceed the dedicated bit space in packed uint256 slots\n                if (o_.supplyExchangePrice > X64 || o_.borrowExchangePrice > X64) {\n                    revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__EXCHANGE_PRICES);\n                }\n                if (utilization_ > X14) {\n                    revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__UTILIZATION);\n                }\n                o_.exchangePricesAndConfig =\n                    (o_.exchangePricesAndConfig &\n                        // mask to update bits: 0-15 (borrow rate), 30-43 (utilization), 58-248 (timestamp, exchange prices, ratios)\n                        0xfe000000000000000000000000000000000000000000000003fff0003fff0000) |\n                    memVar_ | // calcBorrowRateFromUtilization already includes an overflow check\n                    (utilization_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) |\n                    (block.timestamp << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) |\n                    (o_.supplyExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) |\n                    (o_.borrowExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) |\n                    // ratios can never be > 100%, no overflow check needed\n                    (memVar3_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) | // supplyRatio (memVar3_ holds that value)\n                    (memVar4_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO); // borrowRatio (memVar4_ holds that value)\n                // Updating on storage\n                _exchangePricesAndConfig[token_] = o_.exchangePricesAndConfig;\n            } else {\n                // do not update in storage but update o_.exchangePricesAndConfig for updated exchange prices at\n                // event emit of LogOperate\n                o_.exchangePricesAndConfig =\n                    (o_.exchangePricesAndConfig &\n                        // mask to update bits: 91-218 (exchange prices)\n                        0xfffffffffc00000000000000000000000000000007ffffffffffffffffffffff) |\n                    (o_.supplyExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) |\n                    (o_.borrowExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE);\n            }\n        }\n        // sending tokens to user at the end after updating everything\n        // only transfer to user in case of withdraw or borrow.\n        // do not transfer for same amounts in same operate(): supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\n        if ((supplyAmount_ < 0 || borrowAmount_ > 0) && !o_.skipTransfers) {\n            // sending tokens to user at the end after updating everything\n            // set memVar2_ to borrowAmount (if borrow) or reset memVar2_ var to 0 because\n            // it is used with > 0 check below to transfer withdraw / borrow / both\n            memVar2_ = borrowAmount_ > 0 ? uint256(borrowAmount_) : 0;\n            if (supplyAmount_ < 0) {\n                unchecked {\n                    memVar_ = uint256(-supplyAmount_);\n                }\n            } else {\n                memVar_ = 0;\n            }\n            if (memVar_ > 0 && memVar2_ > 0 && withdrawTo_ == borrowTo_) {\n                // if user is doing borrow & withdraw together and address for both is the same\n                // then transfer tokens of borrow & withdraw together to save on gas\n                if (token_ == NATIVE_TOKEN_ADDRESS) {\n                    Address.sendValue(payable(withdrawTo_), memVar_ + memVar2_);\n                } else {\n                    IERC20(token_).safeTransfer(withdrawTo_, memVar_ + memVar2_);\n                }\n            } else {\n                if (token_ == NATIVE_TOKEN_ADDRESS) {\n                    // if withdraw\n                    if (memVar_ > 0) {\n                        Address.sendValue(payable(withdrawTo_), memVar_);\n                    }\n                    // if borrow\n                    if (memVar2_ > 0) {\n                        Address.sendValue(payable(borrowTo_), memVar2_);\n                    }\n                } else {\n                    // if withdraw\n                    if (memVar_ > 0) {\n                        // ---------- temporary code start -----------------------\n                        // temporary addition for weETH: if token is weETH -> withdraw from Zircuit first\n                        if ((token_ == WEETH) && (IERC20(WEETH).balanceOf(address(this)) < memVar_)) {\n                            ZIRCUIT.withdraw(WEETH, memVar_);\n                        }\n                        // temporary code also includes: WEETH & ZIRCUIT constant, IZtakingPool interface\n                        // ---------- temporary code end -----------------------\n\n                        IERC20(token_).safeTransfer(withdrawTo_, memVar_);\n                    }\n                    // if borrow\n                    if (memVar2_ > 0) {\n                        IERC20(token_).safeTransfer(borrowTo_, memVar2_);\n                    }\n                }\n            }\n        }\n        // emit Operate event\n        emit LogOperate(\n            msg.sender,\n            token_,\n            supplyAmount_,\n            borrowAmount_,\n            withdrawTo_,\n            borrowTo_,\n            o_.totalAmounts,\n            o_.exchangePricesAndConfig\n        );\n        // set return values\n        memVar3_ = o_.supplyExchangePrice;\n        memVar4_ = o_.borrowExchangePrice;\n    }\n}\n"
      },
      "solmate/src/utils/FixedPointMathLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\nlibrary FixedPointMathLib {\n    /*//////////////////////////////////////////////////////////////\n                    SIMPLIFIED FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant MAX_UINT256 = 2**256 - 1;\n\n    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\n\n    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\n    }\n\n    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\n    }\n\n    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\n    }\n\n    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\n        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                    LOW LEVEL FIXED POINT OPERATIONS\n    //////////////////////////////////////////////////////////////*/\n\n    function mulDivDown(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // Divide x * y by the denominator.\n            z := div(mul(x, y), denominator)\n        }\n    }\n\n    function mulDivUp(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\n            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\n                revert(0, 0)\n            }\n\n            // If x * y modulo the denominator is strictly greater than 0,\n            // 1 is added to round up the division of x * y by the denominator.\n            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\n        }\n    }\n\n    function rpow(\n        uint256 x,\n        uint256 n,\n        uint256 scalar\n    ) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            switch x\n            case 0 {\n                switch n\n                case 0 {\n                    // 0 ** 0 = 1\n                    z := scalar\n                }\n                default {\n                    // 0 ** n = 0\n                    z := 0\n                }\n            }\n            default {\n                switch mod(n, 2)\n                case 0 {\n                    // If n is even, store scalar in z for now.\n                    z := scalar\n                }\n                default {\n                    // If n is odd, store x in z for now.\n                    z := x\n                }\n\n                // Shifting right by 1 is like dividing by 2.\n                let half := shr(1, scalar)\n\n                for {\n                    // Shift n right by 1 before looping to halve it.\n                    n := shr(1, n)\n                } n {\n                    // Shift n right by 1 each iteration to halve it.\n                    n := shr(1, n)\n                } {\n                    // Revert immediately if x ** 2 would overflow.\n                    // Equivalent to iszero(eq(div(xx, x), x)) here.\n                    if shr(128, x) {\n                        revert(0, 0)\n                    }\n\n                    // Store x squared.\n                    let xx := mul(x, x)\n\n                    // Round to the nearest number.\n                    let xxRound := add(xx, half)\n\n                    // Revert if xx + half overflowed.\n                    if lt(xxRound, xx) {\n                        revert(0, 0)\n                    }\n\n                    // Set x to scaled xxRound.\n                    x := div(xxRound, scalar)\n\n                    // If n is even:\n                    if mod(n, 2) {\n                        // Compute z * x.\n                        let zx := mul(z, x)\n\n                        // If z * x overflowed:\n                        if iszero(eq(div(zx, x), z)) {\n                            // Revert if x is non-zero.\n                            if iszero(iszero(x)) {\n                                revert(0, 0)\n                            }\n                        }\n\n                        // Round to the nearest number.\n                        let zxRound := add(zx, half)\n\n                        // Revert if zx + half overflowed.\n                        if lt(zxRound, zx) {\n                            revert(0, 0)\n                        }\n\n                        // Return properly scaled zxRound.\n                        z := div(zxRound, scalar)\n                    }\n                }\n            }\n        }\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        GENERAL NUMBER UTILITIES\n    //////////////////////////////////////////////////////////////*/\n\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let y := x // We start y at x, which will help us make our initial estimate.\n\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // We check y >= 2^(k + 8) but shift right by k bits\n            // each branch to ensure that if x >= 256, then y >= 256.\n            if iszero(lt(y, 0x10000000000000000000000000000000000)) {\n                y := shr(128, y)\n                z := shl(64, z)\n            }\n            if iszero(lt(y, 0x1000000000000000000)) {\n                y := shr(64, y)\n                z := shl(32, z)\n            }\n            if iszero(lt(y, 0x10000000000)) {\n                y := shr(32, y)\n                z := shl(16, z)\n            }\n            if iszero(lt(y, 0x1000000)) {\n                y := shr(16, y)\n                z := shl(8, z)\n            }\n\n            // Goal was to get z*z*y within a small factor of x. More iterations could\n            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\n            // We ensured y >= 256 so that the relative difference between y and y+1 is small.\n            // That's not possible if x < 256 but we can just verify those cases exhaustively.\n\n            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\n            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\n            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\n\n            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\n            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\n\n            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\n            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\n\n            // There is no overflow risk here since y < 2^136 after the first branch above.\n            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If x+1 is a perfect square, the Babylonian method cycles between\n            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\n            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Mod x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            z := mod(x, y)\n        }\n    }\n\n    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Divide x by y. Note this will return\n            // 0 instead of reverting if y is zero.\n            r := div(x, y)\n        }\n    }\n\n    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Add 1 to x * y if x % y > 0. Note this will\n            // return 0 instead of reverting if y is zero.\n            z := add(gt(mod(x, y), 0), div(x, y))\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 10000000
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}