fluid-contracts-public/deployments/mainnet/solcInputs/28e16643ca0ffa184798260aad7811e6.json
2024-07-11 13:05:09 +00:00

189 lines
354 KiB
JSON

{
"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/token/ERC721/extensions/IERC721Enumerable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Enumerable is IERC721 {\n /**\n * @dev Returns the total amount of tokens stored by the contract.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns a token ID owned by `owner` at a given `index` of its token list.\n * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.\n */\n function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);\n\n /**\n * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.\n * Use along with {totalSupply} to enumerate all tokens.\n */\n function tokenByIndex(uint256 index) external view returns (uint256);\n}\n"
},
"@openzeppelin/contracts/token/ERC721/IERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\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"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts/utils/math/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.2._\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v2.5._\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.2._\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v2.5._\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v2.5._\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v2.5._\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v2.5._\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n *\n * _Available since v3.0._\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n *\n * _Available since v4.7._\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n *\n * _Available since v4.7._\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n *\n * _Available since v4.7._\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n *\n * _Available since v4.7._\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n *\n * _Available since v4.7._\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n *\n * _Available since v4.7._\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n *\n * _Available since v4.7._\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n *\n * _Available since v4.7._\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n *\n * _Available since v4.7._\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n *\n * _Available since v4.7._\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n *\n * _Available since v4.7._\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n *\n * _Available since v4.7._\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n *\n * _Available since v4.7._\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n *\n * _Available since v4.7._\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n *\n * _Available since v4.7._\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n *\n * _Available since v4.7._\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n *\n * _Available since v4.7._\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n *\n * _Available since v4.7._\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n *\n * _Available since v4.7._\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n *\n * _Available since v4.7._\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n *\n * _Available since v4.7._\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n *\n * _Available since v4.7._\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n *\n * _Available since v4.7._\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n *\n * _Available since v4.7._\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n *\n * _Available since v4.7._\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n *\n * _Available since v4.7._\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n *\n * _Available since v3.0._\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n"
},
"contracts/infiniteProxy/interfaces/iProxy.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IProxy {\n function setAdmin(address newAdmin_) external;\n\n function setDummyImplementation(address newDummyImplementation_) external;\n\n function addImplementation(address implementation_, bytes4[] calldata sigs_) external;\n\n function removeImplementation(address implementation_) external;\n\n function getAdmin() external view returns (address);\n\n function getDummyImplementation() external view returns (address);\n\n function getImplementationSigs(address impl_) external view returns (bytes4[] memory);\n\n function getSigsImplementation(bytes4 sig_) external view returns (address);\n\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n"
},
"contracts/libraries/bigMathMinified.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.\n/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision\n/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can\n/// result in significant gas cost reduction due to storage space reduction.\n/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.\n/// @dev roundUp is more like a increase 1, which happens everytime for the same number.\n/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.\nlibrary BigMathMinified {\n /// @dev constants to use for `roundUp` input param to increase readability\n bool internal constant ROUND_DOWN = false;\n bool internal constant ROUND_UP = true;\n\n /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).\n /// e.g.:\n /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]\n /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)\n /// => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000\n /// ^-------------------- 51(exponent) -------------- ^\n /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011 (2236301563)\n /// exponent = 0011,0011 (51)\n /// bigNumber = 1000,0101,0100,1011,0100,0000,1111,1011,0011,0011 (572493200179)\n ///\n /// @param normal number which needs to be converted into Big Number\n /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))\n /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))\n /// @param roundUp signals if result should be rounded down or up\n /// @return bigNumber converted bigNumber (coefficient << exponent)\n function toBigNumber(\n uint256 normal,\n uint256 coefficientSize,\n uint256 exponentSize,\n bool roundUp\n ) internal pure returns (uint256 bigNumber) {\n assembly {\n let lastBit_\n let number_ := normal\n if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit_ := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit_ := add(lastBit_, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit_ := add(lastBit_, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit_ := add(lastBit_, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit_ := add(lastBit_, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit_ := add(lastBit_, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit_ := add(lastBit_, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit_ := add(lastBit_, 1)\n }\n if gt(number_, 0) {\n lastBit_ := add(lastBit_, 1)\n }\n if lt(lastBit_, coefficientSize) {\n // for throw exception\n lastBit_ := coefficientSize\n }\n let exponent := sub(lastBit_, coefficientSize)\n let coefficient := shr(exponent, normal)\n if and(roundUp, gt(exponent, 0)) {\n // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number\n coefficient := add(coefficient, 1)\n if eq(shl(coefficientSize, 1), coefficient) {\n // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits\n // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.\n coefficient := shl(sub(coefficientSize, 1), 1)\n exponent := add(exponent, 1)\n }\n }\n if iszero(lt(exponent, shl(exponentSize, 1))) {\n // if exponent is >= exponentSize, the normal number is too big to fit within\n // BigNumber with too small sizes for coefficient and exponent\n revert(0, 0)\n }\n bigNumber := shl(exponentSize, coefficient)\n bigNumber := add(bigNumber, exponent)\n }\n }\n\n /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`\n function fromBigNumber(\n uint256 bigNumber,\n uint256 exponentSize,\n uint256 exponentMask\n ) internal pure returns (uint256 normal) {\n assembly {\n let coefficient := shr(exponentSize, bigNumber)\n let exponent := and(bigNumber, exponentMask)\n normal := shl(exponent, coefficient)\n }\n }\n\n /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).\n /// e.g.\n /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111\n /// lastBit = ^--------------------------------- 83 ----------------------------------------^\n function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {\n assembly {\n let number_ := normal\n if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit := add(lastBit, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit := add(lastBit, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit := add(lastBit, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit := add(lastBit, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit := add(lastBit, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit := add(lastBit, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit := add(lastBit, 1)\n }\n if gt(number_, 0) {\n lastBit := add(lastBit, 1)\n }\n }\n }\n}\n"
},
"contracts/libraries/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary LibsErrorTypes {\n /***********************************|\n | LiquidityCalcs | \n |__________________________________*/\n\n /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)\n uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;\n\n /// @notice thrown when rate data is set to a version that is not implemented\n uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;\n\n /// @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 /// @dev storage slot for listed tokens array at Liquidity\n uint256 internal constant LIQUIDITY_CONFIGS2_MAPPING_SLOT = 11;\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 uint256 internal constant BITS_EXCHANGE_PRICES_USES_CONFIGS2 = 249;\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 // Configs2\n uint256 internal constant BITS_CONFIGS2_MAX_UTILIZATION = 0;\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/libraries/tickMath.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that calculates number \"tick\" and \"ratioX96\" from this: ratioX96 = (1.0015^tick) * 2^96\n/// @notice this library is used in Fluid Vault protocol for optimiziation.\n/// @dev \"tick\" supports between -32767 and 32767. \"ratioX96\" supports between 37075072 and 169307877264527972847801929085841449095838922544595\nlibrary TickMath {\n /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767\n int24 internal constant MIN_TICK = -32767;\n /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767\n int24 internal constant MAX_TICK = 32767;\n\n uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;\n uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631\n uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176\n uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073\n uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163\n uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875\n uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178\n uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664\n uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 \n uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087\n uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449\n uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131\n uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661\n uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e; // 2^128/1.0015**4096 = 733725103481409245883800626999235102\n uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77; // 2^128/1.0015**8192 = 1582075887005588088019997442108535\n uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10; // 2^128/1.0015**16384 = 7355550435635883087458926352\n\n /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`\n uint256 internal constant MIN_RATIOX96 = 37075072;\n /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).\n /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference\n uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;\n\n uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336\n uint256 internal constant _1E26 = 1e26;\n\n /// @notice ratioX96 = (1.0015^tick) * 2^96\n /// @dev Throws if |tick| > max tick\n /// @param tick The input tick for the above formula\n /// @return ratioX96 ratio = (debt amount/collateral amount)\n function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {\n assembly {\n let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))\n\n if gt(absTick_, MAX_TICK) {\n revert(0, 0)\n }\n let factor_ := FACTOR00\n if and(absTick_, 0x1) {\n factor_ := FACTOR01\n }\n if and(absTick_, 0x2) {\n factor_ := shr(128, mul(factor_, FACTOR02))\n }\n if and(absTick_, 0x4) {\n factor_ := shr(128, mul(factor_, FACTOR03))\n }\n if and(absTick_, 0x8) {\n factor_ := shr(128, mul(factor_, FACTOR04))\n }\n if and(absTick_, 0x10) {\n factor_ := shr(128, mul(factor_, FACTOR05))\n }\n if and(absTick_, 0x20) {\n factor_ := shr(128, mul(factor_, FACTOR06))\n }\n if and(absTick_, 0x40) {\n factor_ := shr(128, mul(factor_, FACTOR07))\n }\n if and(absTick_, 0x80) {\n factor_ := shr(128, mul(factor_, FACTOR08))\n }\n if and(absTick_, 0x100) {\n factor_ := shr(128, mul(factor_, FACTOR09))\n }\n if and(absTick_, 0x200) {\n factor_ := shr(128, mul(factor_, FACTOR10))\n }\n if and(absTick_, 0x400) {\n factor_ := shr(128, mul(factor_, FACTOR11))\n }\n if and(absTick_, 0x800) {\n factor_ := shr(128, mul(factor_, FACTOR12))\n }\n if and(absTick_, 0x1000) {\n factor_ := shr(128, mul(factor_, FACTOR13))\n }\n if and(absTick_, 0x2000) {\n factor_ := shr(128, mul(factor_, FACTOR14))\n }\n if and(absTick_, 0x4000) {\n factor_ := shr(128, mul(factor_, FACTOR15))\n }\n\n let precision_ := 0\n if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {\n factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)\n // we round up in the division so getTickAtRatio of the output price is always consistent\n if mod(factor_, 0x100000000) {\n precision_ := 1\n }\n }\n ratioX96 := add(shr(32, factor_), precision_)\n }\n }\n\n /// @notice ratioX96 = (1.0015^tick) * 2^96\n /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio\n /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)\n /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124\n /// @return perfectRatioX96 perfect ratio for the above tick\n function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {\n assembly {\n if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {\n revert(0, 0)\n }\n\n let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)\n let factor_\n\n if iszero(cond) {\n // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)\n }\n if cond {\n // ratioX96 < ZERO_TICK_SCALED_RATIO\n factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)\n }\n\n // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336\n\n // for tick = 16384\n // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735\n // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =\n // 4626198540796508716348404308345255985.06131964639489434655721\n if iszero(lt(factor_, 4626198540796508716348404308345255985)) {\n tick := or(tick, 0x4000)\n factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)\n }\n // for tick = 8192\n // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865\n // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =\n // 21508599537851153911767490449162.3037648642153898377655505172\n if iszero(lt(factor_, 21508599537851153911767490449162)) {\n tick := or(tick, 0x2000)\n factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)\n }\n // for tick = 4096\n // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150\n // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =\n // 46377364670549310883002866648.9777607649742626173648716941385\n if iszero(lt(factor_, 46377364670549310883002866649)) {\n tick := or(tick, 0x1000)\n factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)\n }\n // for tick = 2048\n // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335\n // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =\n // 2153540449365864845468344760.06357108484096046743300420319322\n if iszero(lt(factor_, 2153540449365864845468344760)) {\n tick := or(tick, 0x800)\n factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)\n }\n // for tick = 1024\n // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236\n // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =\n // 464062544207767844008185024.950588990554136265212906454481127\n if iszero(lt(factor_, 464062544207767844008185025)) {\n tick := or(tick, 0x400)\n factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)\n }\n // for tick = 512\n // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668\n // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =\n // 215421109505955298802281577.031879604792139232258508172947569\n if iszero(lt(factor_, 215421109505955298802281577)) {\n tick := or(tick, 0x200)\n factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)\n }\n // for tick = 256\n // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301\n // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =\n // 146772309890508740607270614.667650899656438875541505058062410\n if iszero(lt(factor_, 146772309890508740607270615)) {\n tick := or(tick, 0x100)\n factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)\n }\n // for tick = 128\n // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590\n // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =\n // 121149622323187099817270416.157248837742741760456796835775887\n if iszero(lt(factor_, 121149622323187099817270416)) {\n tick := or(tick, 0x80)\n factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)\n }\n // for tick = 64\n // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124\n // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =\n // 110067989135437147685980801.568068573422377364214113968609839\n if iszero(lt(factor_, 110067989135437147685980801)) {\n tick := or(tick, 0x40)\n factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)\n }\n // for tick = 32\n // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475\n // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =\n // 104913292358707887270979599.831816586773651266562785765558183\n if iszero(lt(factor_, 104913292358707887270979600)) {\n tick := or(tick, 0x20)\n factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)\n }\n // for tick = 16\n // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176\n // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =\n // 102427189924701091191840927.762844039579442328381455567932128\n if iszero(lt(factor_, 102427189924701091191840928)) {\n tick := or(tick, 0x10)\n factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)\n }\n // for tick = 8\n // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620\n // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =\n // 101206318935480056907421312.890625\n if iszero(lt(factor_, 101206318935480056907421313)) {\n tick := or(tick, 0x8)\n factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)\n }\n // for tick = 4\n // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603\n // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =\n // 100601351350506250000000000\n if iszero(lt(factor_, 100601351350506250000000000)) {\n tick := or(tick, 0x4)\n factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)\n }\n // for tick = 2\n // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660\n // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =\n // 100300225000000000000000000\n if iszero(lt(factor_, 100300225000000000000000000)) {\n tick := or(tick, 0x2)\n factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)\n }\n // for tick = 1\n // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261\n // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =\n // 100150000000000000000000000\n if iszero(lt(factor_, 100150000000000000000000000)) {\n tick := or(tick, 0x1)\n factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)\n }\n if iszero(cond) {\n // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)\n }\n if cond {\n // ratioX96 < ZERO_TICK_SCALED_RATIO\n tick := not(tick)\n perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)\n }\n // perfect ratio should always be <= ratioX96\n // not sure if it can ever be bigger but better to have extra checks\n if gt(perfectRatioX96, ratioX96) {\n revert(0, 0)\n }\n }\n }\n}\n"
},
"contracts/liquidity/adminModule/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Structs {\n struct AddressBool {\n address addr;\n bool value;\n }\n\n struct AddressUint256 {\n address addr;\n uint256 value;\n }\n\n /// @notice struct to set borrow rate data for version 1\n struct RateDataV1Params {\n ///\n /// @param token for rate data\n address token;\n ///\n /// @param kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink usually means slow increase in rate, once utilization is above kink borrow rate increases fast\n uint256 kink;\n ///\n /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n /// i.e. constant minimum borrow rate\n /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n uint256 rateAtUtilizationZero;\n ///\n /// @param rateAtUtilizationKink borrow rate when utilization is at kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at kink then rateAtUtilizationKink would be 700\n uint256 rateAtUtilizationKink;\n ///\n /// @param rateAtUtilizationMax borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n uint256 rateAtUtilizationMax;\n }\n\n /// @notice struct to set borrow rate data for version 2\n struct RateDataV2Params {\n ///\n /// @param token for rate data\n address token;\n ///\n /// @param kink1 first kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink 1 usually means slow increase in rate, once utilization is above kink 1 borrow rate increases faster\n uint256 kink1;\n ///\n /// @param kink2 second kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink 2 usually means slow / medium increase in rate, once utilization is above kink 2 borrow rate increases fast\n uint256 kink2;\n ///\n /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n /// i.e. constant minimum borrow rate\n /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n uint256 rateAtUtilizationZero;\n ///\n /// @param rateAtUtilizationKink1 desired borrow rate when utilization is at first kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at first kink then rateAtUtilizationKink would be 700\n uint256 rateAtUtilizationKink1;\n ///\n /// @param rateAtUtilizationKink2 desired borrow rate when utilization is at second kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at second kink then rateAtUtilizationKink would be 1_200\n uint256 rateAtUtilizationKink2;\n ///\n /// @param rateAtUtilizationMax desired borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n uint256 rateAtUtilizationMax;\n }\n\n /// @notice struct to set token config\n struct TokenConfig {\n ///\n /// @param token address\n address token;\n ///\n /// @param fee charges on borrower's interest. in 1e2: 100% = 10_000; 1% = 100\n uint256 fee;\n ///\n /// @param threshold on when to update the storage slot. in 1e2: 100% = 10_000; 1% = 100\n uint256 threshold;\n ///\n /// @param maxUtilization maximum allowed utilization. in 1e2: 100% = 10_000; 1% = 100\n /// set to 100% to disable and have default limit of 100% (avoiding SLOAD).\n uint256 maxUtilization;\n }\n\n /// @notice struct to set user supply & withdrawal config\n struct UserSupplyConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which withdrawal limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration withdrawal limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseWithdrawalLimit;\n }\n\n /// @notice struct to set user borrow & payback config\n struct UserBorrowConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which debt limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration debt limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling\n /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseDebtCeiling;\n ///\n /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 maxDebtCeiling;\n }\n}\n"
},
"contracts/liquidity/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 /// @dev decimals for native token\n // !! Double check compatibility with all code if this ever changes for a deployment !!\n uint8 internal constant NATIVE_TOKEN_DECIMALS = 18;\n\n /// @dev Minimum token decimals for any token that can be listed at Liquidity (inclusive)\n uint8 internal constant MIN_TOKEN_DECIMALS = 6;\n /// @dev Maximum token decimals for any token that can be listed at Liquidity (inclusive)\n uint8 internal constant MAX_TOKEN_DECIMALS = 18;\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 /// Next 1 bit => 249-249 => flag for token uses config storage slot 2. (signals SLOAD for additional config slot is needed during execution)\n /// Last 6 bits => 250-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 // ----- storage slot 11 ------\n\n /// @dev expanded token configs per token: token -> config data slot 2.\n /// Use of this is signaled by `_exchangePricesAndConfig` bit 249.\n /// First 14 bits => 0- 13 => max allowed utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\n /// Last 242 bits => 14-255 => empty for future use\n mapping(address => uint256) internal _configs2;\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 uint256 internal constant AdminModule__ValueOverflow__MAX_UTILIZATION = 10027;\n\n /// @notice thrown if a token that is being listed has not between 6 and 18 decimals\n uint256 internal constant AdminModule__TokenInvalidDecimalsRange = 10028;\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/interfaces/iLiquidity.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IProxy } from \"../../infiniteProxy/interfaces/iProxy.sol\";\nimport { Structs as AdminModuleStructs } from \"../adminModule/structs.sol\";\n\ninterface IFluidLiquidityAdmin {\n /// @notice adds/removes auths. Auths generally could be contracts which can have restricted actions defined on contract.\n /// auths can be helpful in reducing governance overhead where it's not needed.\n /// @param authsStatus_ array of structs setting allowed status for an address.\n /// status true => add auth, false => remove auth\n function updateAuths(AdminModuleStructs.AddressBool[] calldata authsStatus_) external;\n\n /// @notice adds/removes guardians. Only callable by Governance.\n /// @param guardiansStatus_ array of structs setting allowed status for an address.\n /// status true => add guardian, false => remove guardian\n function updateGuardians(AdminModuleStructs.AddressBool[] calldata guardiansStatus_) external;\n\n /// @notice changes the revenue collector address (contract that is sent revenue). Only callable by Governance.\n /// @param revenueCollector_ new revenue collector address\n function updateRevenueCollector(address revenueCollector_) external;\n\n /// @notice changes current status, e.g. for pausing or unpausing all user operations. Only callable by Auths.\n /// @param newStatus_ new status\n /// status = 2 -> pause, status = 1 -> resume.\n function changeStatus(uint256 newStatus_) external;\n\n /// @notice update tokens rate data version 1. Only callable by Auths.\n /// @param tokensRateData_ array of RateDataV1Params with rate data to set for each token\n function updateRateDataV1s(AdminModuleStructs.RateDataV1Params[] calldata tokensRateData_) external;\n\n /// @notice update tokens rate data version 2. Only callable by Auths.\n /// @param tokensRateData_ array of RateDataV2Params with rate data to set for each token\n function updateRateDataV2s(AdminModuleStructs.RateDataV2Params[] calldata tokensRateData_) external;\n\n /// @notice updates token configs: fee charge on borrowers interest & storage update utilization threshold.\n /// Only callable by Auths.\n /// @param tokenConfigs_ contains token address, fee & utilization threshold\n function updateTokenConfigs(AdminModuleStructs.TokenConfig[] calldata tokenConfigs_) external;\n\n /// @notice updates user classes: 0 is for new protocols, 1 is for established protocols.\n /// Only callable by Auths.\n /// @param userClasses_ struct array of uint256 value to assign for each user address\n function updateUserClasses(AdminModuleStructs.AddressUint256[] calldata userClasses_) external;\n\n /// @notice sets user supply configs per token basis. Eg: with interest or interest-free and automated limits.\n /// Only callable by Auths.\n /// @param userSupplyConfigs_ struct array containing user supply config, see `UserSupplyConfig` struct for more info\n function updateUserSupplyConfigs(AdminModuleStructs.UserSupplyConfig[] memory userSupplyConfigs_) external;\n\n /// @notice setting user borrow configs per token basis. Eg: with interest or interest-free and automated limits.\n /// Only callable by Auths.\n /// @param userBorrowConfigs_ struct array containing user borrow config, see `UserBorrowConfig` struct for more info\n function updateUserBorrowConfigs(AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_) external;\n\n /// @notice pause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n /// Only callable by Guardians.\n /// @param user_ address of user to pause operations for\n /// @param supplyTokens_ token addresses to pause withdrawals for\n /// @param borrowTokens_ token addresses to pause borrowings for\n function pauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n /// @notice unpause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n /// Only callable by Guardians.\n /// @param user_ address of user to unpause operations for\n /// @param supplyTokens_ token addresses to unpause withdrawals for\n /// @param borrowTokens_ token addresses to unpause borrowings for\n function unpauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n /// @notice collects revenue for tokens to configured revenueCollector address.\n /// @param tokens_ array of tokens to collect revenue for\n /// @dev Note that this can revert if token balance is < revenueAmount (utilization > 100%)\n function collectRevenue(address[] calldata tokens_) external;\n\n /// @notice gets the current updated exchange prices for n tokens and updates all prices, rates related data in storage.\n /// @param tokens_ tokens to update exchange prices for\n /// @return supplyExchangePrices_ new supply rates of overall system for each token\n /// @return borrowExchangePrices_ new borrow rates of overall system for each token\n function updateExchangePrices(\n address[] calldata tokens_\n ) external returns (uint256[] memory supplyExchangePrices_, uint256[] memory borrowExchangePrices_);\n}\n\ninterface IFluidLiquidityLogic is IFluidLiquidityAdmin {\n /// @notice Single function which handles supply, withdraw, borrow & payback\n /// @param token_ address of token (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native)\n /// @param supplyAmount_ if +ve then supply, if -ve then withdraw, if 0 then nothing\n /// @param borrowAmount_ if +ve then borrow, if -ve then payback, if 0 then nothing\n /// @param withdrawTo_ if withdrawal then to which address\n /// @param borrowTo_ if borrow then to which address\n /// @param callbackData_ callback data passed to `liquidityCallback` method of protocol\n /// @return memVar3_ updated supplyExchangePrice\n /// @return memVar4_ updated borrowExchangePrice\n /// @dev to trigger skipping in / out transfers when in&out amounts balance themselves out (gas optimization):\n /// - supply(+) == borrow(+), withdraw(-) == payback(-).\n /// - `withdrawTo_` / `borrowTo_` must be msg.sender (protocol)\n /// - `callbackData_` MUST be encoded so that \"from\" address is at last 20 bytes (if this optimization is desired),\n /// also for native token operations where liquidityCallback is not triggered!\n /// from address must come at last position if there is more data. I.e. encode like:\n /// abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end\n /// so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end.\n function operate(\n address token_,\n int256 supplyAmount_,\n int256 borrowAmount_,\n address withdrawTo_,\n address borrowTo_,\n bytes calldata callbackData_\n ) external payable returns (uint256 memVar3_, uint256 memVar4_);\n}\n\ninterface IFluidLiquidity is IProxy, IFluidLiquidityLogic {}\n"
},
"contracts/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\n // for borrow operations, ensure max utilization is not reached\n if (borrowAmount_ > 0) {\n // memVar_ => max utilization\n // if any max utilization other than 100% is set, the flag usesConfigs2 in\n // exchangePricesAndConfig is 1. (optimized to avoid SLOAD if not needed).\n memVar_ = (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_USES_CONFIGS2) &\n 1 ==\n 1\n ? (_configs2[token_] & X14) // read configured max utilization\n : FOUR_DECIMALS; // default max utilization = 100%\n\n if (utilization_ > memVar_) {\n revert FluidLiquidityError(ErrorTypes.UserModule__MaxUtilizationReached);\n }\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"
},
"contracts/liquidity/weETHTransferModule/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { Variables } from \"../common/variables.sol\";\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 function balance(address token_, address staker_) external view returns (uint256);\n}\n\ncontract FluidLiquidityWeETHZircuitTransferModule is Variables {\n address internal constant LIQUIDITY = 0x52Aa899454998Be5b000Ad077a46Bbe360F4e497;\n\n IERC20 internal constant WEETH = IERC20(0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee);\n IZtakingPool internal constant ZIRCUIT = IZtakingPool(0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6);\n\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 /// @notice deposit all WEETH funds to Zircuit and sets approved allowance to max uint256.\n /// @dev Only delegate callable on Liquidity, by Governance\n function depositZircuit() external {\n if (_getGovernanceAddr() != msg.sender || address(this) != LIQUIDITY) {\n revert();\n }\n\n SafeERC20.safeApprove(WEETH, address(ZIRCUIT), type(uint256).max);\n\n ZIRCUIT.depositFor(address(WEETH), address(this), WEETH.balanceOf(address(this)));\n }\n\n /// @notice withdraw all WEETH funds from Zircuit and sets approved allowance to 0.\n /// @dev Only delegate callable on Liquidity, Governance and Guardians (for emergency)\n function withdrawZircuit() external {\n if ((_isGuardian[msg.sender] & 1 != 1 && _getGovernanceAddr() != msg.sender) || address(this) != LIQUIDITY) {\n revert();\n }\n\n ZIRCUIT.withdraw(address(WEETH), ZIRCUIT.balance(address(WEETH), address(this)));\n\n // remove approval\n SafeERC20.safeApprove(WEETH, address(ZIRCUIT), 0);\n }\n}\n"
},
"contracts/mocks/mockProtocol.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { FluidLiquidityUserModule } from \"../liquidity/userModule/main.sol\";\nimport { IFluidLiquidity } from \"../liquidity/interfaces/iLiquidity.sol\";\n\n/// @title Mock Protocol\n/// @notice Mock protocol for testing, implements:\n/// function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external;\n/// This callback method MUST transferFrom data_ decoded from address to the liquidity contract\ncontract MockProtocol {\n using SafeERC20 for IERC20;\n\n /// @dev address that is mapped to the chain native token\n address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n address public immutable liquidityContract;\n\n /// @notice thrown when liquidity callback is called for a native token operation\n error MockProtocol__UnexpectedLiquidityCallback();\n\n bool transferInsufficientMode = false;\n bool transferExcessMode = false;\n bool reentrancyFromCallback = false;\n address transferFromAddress;\n\n /// @notice Construct a new MockProtocol\n /// @param liquidityContract_ The address of the liquidity contract\n constructor(address liquidityContract_) {\n liquidityContract = liquidityContract_;\n }\n\n receive() external payable {}\n\n function setTransferInsufficientMode(bool transferInsufficientMode_) public {\n transferInsufficientMode = transferInsufficientMode_;\n }\n\n function setTransferExcessMode(bool transferExcessMode_) public {\n transferExcessMode = transferExcessMode_;\n }\n\n function setReentrancyFromCallback(bool reentrancyFromCallback_) public {\n reentrancyFromCallback = reentrancyFromCallback_;\n }\n\n function setTransferFromAddress(address transferFromAddress_) public {\n transferFromAddress = transferFromAddress_;\n }\n\n /// @notice Mock liquidity callback\n /// @param token_ The token being transferred\n /// @param amount_ The amount being transferred\n function liquidityCallback(address token_, uint256 amount_, bytes memory data_) external {\n if (reentrancyFromCallback) {\n // call operate with some random values (should not matter as it reverts anyway)\n IFluidLiquidity(liquidityContract).operate(token_, 10, 0, address(0), address(0), abi.encode(address(this)));\n }\n\n if (token_ == NATIVE_TOKEN_ADDRESS) {\n revert MockProtocol__UnexpectedLiquidityCallback();\n }\n\n address from_;\n if (transferFromAddress == address(0)) {\n // take the last 20 bytes of data_ and decode them to address. Gives more flexibility in type of\n // data that can be passed in to Liquidity at mock calls while ensuring mock Protocol can do what it\n // is supposed to do: transfer amount of token to liquidity.\n assembly {\n from_ := mload(\n add(\n // add padding for length as present for dynamic arrays in memory\n add(data_, 32),\n // assembly expects address with leading zeros / left padded so need to use 32 as length here\n sub(mload(data_), 32)\n )\n )\n }\n } else {\n from_ = transferFromAddress;\n }\n\n if (amount_ > 0) {\n if (transferExcessMode) {\n amount_ += 1e6;\n } else if (transferInsufficientMode) {\n amount_ -= 1;\n }\n }\n\n if (from_ == address(this)) {\n // use approve and transferFrom for more consistent testing of methods called\n // (always transferFrom instead of transfer)\n IERC20(token_).safeApprove(address(this), amount_);\n IERC20(token_).safeTransferFrom(address(this), liquidityContract, amount_);\n } else {\n IERC20(token_).safeTransferFrom(from_, liquidityContract, amount_);\n }\n }\n\n /// @notice Proxy method for executing `operate` on the liquidity contract\n function operate(\n address token_,\n int256 supplyAmount_,\n int256 borrowAmount_,\n address withdrawTo_,\n address borrowTo_,\n bytes calldata callbackData_\n ) external payable returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {\n uint256 valueAmount = msg.value;\n\n if (valueAmount > 0) {\n if (transferExcessMode) {\n valueAmount += 1e9 + 1;\n } else if (transferInsufficientMode) {\n valueAmount -= 1;\n }\n }\n\n return\n FluidLiquidityUserModule(liquidityContract).operate{ value: valueAmount }(\n token_,\n supplyAmount_,\n borrowAmount_,\n withdrawTo_,\n borrowTo_,\n callbackData_\n );\n }\n}\n"
},
"contracts/oracle/fluidOracle.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidOracle } from \"./interfaces/iFluidOracle.sol\";\n\n/// @title FluidOracle\n/// @notice Base contract that any Fluid Oracle must implement\nabstract contract FluidOracle is IFluidOracle {\n /// @inheritdoc IFluidOracle\n function getExchangeRate() external view virtual returns (uint256 exchangeRate_);\n\n /// @inheritdoc IFluidOracle\n function getExchangeRateOperate() external view virtual returns (uint256 exchangeRate_);\n\n /// @inheritdoc IFluidOracle\n function getExchangeRateLiquidate() external view virtual returns (uint256 exchangeRate_);\n}\n"
},
"contracts/oracle/interfaces/iFluidOracle.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidOracle {\n /// @dev Deprecated. Use `getExchangeRateOperate()` and `getExchangeRateLiquidate()` instead. Only implemented for\n /// backwards compatibility.\n function getExchangeRate() external view returns (uint256 exchangeRate_);\n\n /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for operates\n function getExchangeRateOperate() external view returns (uint256 exchangeRate_);\n\n /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for liquidations\n function getExchangeRateLiquidate() external view returns (uint256 exchangeRate_);\n}\n"
},
"contracts/periphery/resolvers/liquidity/iLiquidityResolver.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs as LiquidityStructs } from \"../../../periphery/resolvers/liquidity/structs.sol\";\n\ninterface IFluidLiquidityResolver {\n /// @notice gets the `revenueAmount_` for a `token_`.\n function getRevenue(address token_) external view returns (uint256 revenueAmount_);\n\n /// @notice address of contract that gets sent the revenue. Configurable by governance\n function getRevenueCollector() external view returns (address);\n\n /// @notice Liquidity contract paused status: status = 1 -> normal. status = 2 -> paused.\n function getStatus() external view returns (uint256);\n\n /// @notice checks if `auth_` is an allowed auth on Liquidity.\n /// Auths can set most config values. E.g. contracts that automate certain flows like e.g. adding a new fToken.\n /// Governance can add/remove auths. Governance is auth by default.\n function isAuth(address auth_) external view returns (uint256);\n\n /// @notice checks if `guardian_` is an allowed Guardian on Liquidity.\n /// Guardians can pause lower class users.\n /// Governance can add/remove guardians. Governance is guardian by default.\n function isGuardian(address guardian_) external view returns (uint256);\n\n /// @notice gets user class for `user_`. Class defines which protocols can be paused by guardians.\n /// Currently there are 2 classes: 0 can be paused by guardians. 1 cannot be paused by guardians.\n /// New protocols are added as class 0 and will be upgraded to 1 over time.\n function getUserClass(address user_) external view returns (uint256);\n\n /// @notice gets exchangePricesAndConfig packed uint256 storage slot for `token_`.\n function getExchangePricesAndConfig(address token_) external view returns (uint256);\n\n /// @notice gets rateConfig packed uint256 storage slot for `token_`.\n function getRateConfig(address token_) external view returns (uint256);\n\n /// @notice gets totalAmounts packed uint256 storage slot for `token_`.\n function getTotalAmounts(address token_) external view returns (uint256);\n\n /// @notice gets configs2 packed uint256 storage slot for `token_`.\n function getConfigs2(address token_) external view returns (uint256);\n\n /// @notice gets userSupply data packed uint256 storage slot for `user_` and `token_`.\n function getUserSupply(address user_, address token_) external view returns (uint256);\n\n /// @notice gets userBorrow data packed uint256 storage slot for `user_` and `token_`.\n function getUserBorrow(address user_, address token_) external view returns (uint256);\n\n /// @notice returns all `listedTokens_` at the Liquidity contract. Once configured, a token can never be removed.\n function listedTokens() external view returns (address[] memory listedTokens_);\n\n /// @notice get the Rate config data `rateData_` for a `token_` compiled from the packed uint256 rateConfig storage slot\n function getTokenRateData(address token_) external view returns (LiquidityStructs.RateData memory rateData_);\n\n /// @notice get the Rate config datas `rateDatas_` for multiple `tokens_` compiled from the packed uint256 rateConfig storage slot\n function getTokensRateData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.RateData[] memory rateDatas_);\n\n /// @notice returns general data for `token_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokenData(\n address token_\n ) external view returns (LiquidityStructs.OverallTokenData memory overallTokenData_);\n\n /// @notice returns general data for multiple `tokens_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokensData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);\n\n /// @notice returns general data for all `listedTokens()` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getAllOverallTokensData()\n external\n view\n returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserSupplyData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData memory userSupplyData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleSupplyData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserBorrowData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData memory userBorrowData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleBorrowData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `supplyTokens_`\n /// and returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `borrowTokens_`\n function getUserMultipleBorrowSupplyData(\n address user_,\n address[] calldata supplyTokens_,\n address[] calldata borrowTokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallSupplyTokensData_,\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallBorrowTokensData_\n );\n}\n"
},
"contracts/periphery/resolvers/liquidity/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport { LiquidityCalcs } from \"../../../libraries/liquidityCalcs.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidLiquidityResolver } from \"./iLiquidityResolver.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { Variables } from \"./variables.sol\";\n\ninterface TokenInterface {\n function balanceOf(address) external view returns (uint);\n}\n\ninterface IZtakingPool {\n function balance(address token_, address staker_) external view returns (uint256);\n}\n\n/// @notice Fluid Liquidity resolver\n/// Implements various view-only methods to give easy access to Liquidity data.\ncontract FluidLiquidityResolver is IFluidLiquidityResolver, Variables, Structs {\n /// @dev address that is mapped to the chain native token\n address internal constant _NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice thrown if an input param address is zero\n error FluidLiquidityResolver__AddressZero();\n\n constructor(IFluidLiquidity liquidity_) Variables(liquidity_) {\n if (address(liquidity_) == address(0)) {\n revert FluidLiquidityResolver__AddressZero();\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getRevenueCollector() public view returns (address) {\n return address(uint160(LIQUIDITY.readFromStorage(bytes32(0))));\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getRevenue(address token_) public view returns (uint256 revenueAmount_) {\n uint256 liquidityTokenBalance_ = token_ == _NATIVE_TOKEN_ADDRESS\n ? address(LIQUIDITY).balance\n : IERC20(token_).balanceOf(address(LIQUIDITY));\n\n uint256 exchangePricesAndConfig_ = getExchangePricesAndConfig(token_);\n if (exchangePricesAndConfig_ == 0) {\n return 0;\n }\n\n return LiquidityCalcs.calcRevenue(getTotalAmounts(token_), exchangePricesAndConfig_, liquidityTokenBalance_);\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getStatus() public view returns (uint256) {\n return LIQUIDITY.readFromStorage(bytes32(LiquiditySlotsLink.LIQUIDITY_STATUS_SLOT));\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function isAuth(address auth_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(LiquiditySlotsLink.LIQUIDITY_AUTHS_MAPPING_SLOT, auth_)\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function isGuardian(address guardian_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_GUARDIANS_MAPPING_SLOT,\n guardian_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserClass(address user_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_USER_CLASS_MAPPING_SLOT,\n user_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getExchangePricesAndConfig(address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getRateConfig(address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_RATE_DATA_MAPPING_SLOT,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getTotalAmounts(address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getConfigs2(address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_CONFIGS2_MAPPING_SLOT,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserSupply(address user_, address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateDoubleMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT,\n user_,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserBorrow(address user_, address token_) public view returns (uint256) {\n return\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateDoubleMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT,\n user_,\n token_\n )\n );\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function listedTokens() public view returns (address[] memory listedTokens_) {\n uint256 length_ = LIQUIDITY.readFromStorage(bytes32(LiquiditySlotsLink.LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT));\n\n listedTokens_ = new address[](length_);\n\n uint256 startingSlotForArrayElements_ = uint256(\n keccak256(abi.encode(LiquiditySlotsLink.LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT))\n );\n\n for (uint256 i; i < length_; i++) {\n listedTokens_[i] = address(uint160(LIQUIDITY.readFromStorage(bytes32(startingSlotForArrayElements_ + i))));\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getTokenRateData(address token_) public view returns (RateData memory rateData_) {\n uint256 rateConfig_ = getRateConfig(token_);\n\n rateData_.version = rateConfig_ & 0xF;\n\n if (rateData_.version == 1) {\n rateData_.rateDataV1.rateAtUtilizationZero =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) &\n X16;\n rateData_.rateDataV1.kink = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;\n rateData_.rateDataV1.rateAtUtilizationKink =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) &\n X16;\n rateData_.rateDataV1.rateAtUtilizationMax =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) &\n X16;\n } else if (rateData_.version == 2) {\n rateData_.rateDataV2.rateAtUtilizationZero =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) &\n X16;\n rateData_.rateDataV2.kink1 =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) &\n X16;\n rateData_.rateDataV2.rateAtUtilizationKink1 =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) &\n X16;\n rateData_.rateDataV2.kink2 =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) &\n X16;\n rateData_.rateDataV2.rateAtUtilizationKink2 =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) &\n X16;\n rateData_.rateDataV2.rateAtUtilizationMax =\n (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) &\n X16;\n } else if (rateData_.version > 0) {\n // when version is 0 -> token not configured yet. do not revert, just return 0 for all values\n revert(\"not-valid-rate-version\");\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getTokensRateData(address[] calldata tokens_) public view returns (RateData[] memory rateDatas_) {\n uint256 length_ = tokens_.length;\n rateDatas_ = new RateData[](length_);\n\n for (uint256 i; i < length_; i++) {\n rateDatas_[i] = getTokenRateData(tokens_[i]);\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getOverallTokenData(\n address token_\n ) public view returns (Structs.OverallTokenData memory overallTokenData_) {\n overallTokenData_.rateData = getTokenRateData(token_);\n\n uint256 exchangePriceAndConfig_ = getExchangePricesAndConfig(token_);\n if (exchangePriceAndConfig_ > 0) {\n uint256 totalAmounts_ = getTotalAmounts(token_);\n\n (overallTokenData_.supplyExchangePrice, overallTokenData_.borrowExchangePrice) = LiquidityCalcs\n .calcExchangePrices(exchangePriceAndConfig_);\n\n overallTokenData_.borrowRate = exchangePriceAndConfig_ & X16;\n overallTokenData_.fee = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14;\n overallTokenData_.lastStoredUtilization =\n (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) &\n X14;\n overallTokenData_.storageUpdateThreshold =\n (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD) &\n X14;\n overallTokenData_.lastUpdateTimestamp =\n (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) &\n X33;\n overallTokenData_.maxUtilization = FOUR_DECIMALS;\n if ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_USES_CONFIGS2) & 1 == 1) {\n overallTokenData_.maxUtilization = getConfigs2(token_) & X14;\n }\n\n // Extract supply & borrow amounts\n uint256 temp_ = totalAmounts_ & X64;\n overallTokenData_.supplyRawInterest = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n overallTokenData_.supplyInterestFree = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n overallTokenData_.borrowRawInterest = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n overallTokenData_.borrowInterestFree = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n uint256 supplyWithInterest_;\n uint256 borrowWithInterest_;\n if (overallTokenData_.supplyRawInterest > 0) {\n // use old exchange prices for supply rate to be at same level as borrow rate from storage.\n // Note the rate here can be a tiny bit with higher precision because we use borrowWithInterest_ / supplyWithInterest_\n // which has higher precision than the utilization used from storage in LiquidityCalcs\n supplyWithInterest_ =\n (overallTokenData_.supplyRawInterest *\n ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &\n X64)) /\n EXCHANGE_PRICES_PRECISION; // normalized from raw\n borrowWithInterest_ =\n (overallTokenData_.borrowRawInterest *\n ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &\n X64)) /\n EXCHANGE_PRICES_PRECISION; // normalized from raw\n\n overallTokenData_.supplyRate = supplyWithInterest_ == 0\n ? 0\n : (overallTokenData_.borrowRate * (FOUR_DECIMALS - overallTokenData_.fee) * borrowWithInterest_) /\n (supplyWithInterest_ * FOUR_DECIMALS);\n }\n\n supplyWithInterest_ =\n (overallTokenData_.supplyRawInterest * overallTokenData_.supplyExchangePrice) /\n EXCHANGE_PRICES_PRECISION; // normalized from raw\n overallTokenData_.totalSupply = supplyWithInterest_ + overallTokenData_.supplyInterestFree;\n borrowWithInterest_ =\n (overallTokenData_.borrowRawInterest * overallTokenData_.borrowExchangePrice) /\n EXCHANGE_PRICES_PRECISION; // normalized from raw\n overallTokenData_.totalBorrow = borrowWithInterest_ + overallTokenData_.borrowInterestFree;\n\n overallTokenData_.revenue = getRevenue(token_);\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getOverallTokensData(\n address[] memory tokens_\n ) public view returns (Structs.OverallTokenData[] memory overallTokensData_) {\n uint256 length_ = tokens_.length;\n overallTokensData_ = new Structs.OverallTokenData[](length_);\n for (uint256 i; i < length_; i++) {\n overallTokensData_[i] = getOverallTokenData(tokens_[i]);\n }\n }\n\n address private constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;\n IZtakingPool private constant ZIRCUIT = IZtakingPool(0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6);\n\n /// @inheritdoc IFluidLiquidityResolver\n function getAllOverallTokensData() public view returns (Structs.OverallTokenData[] memory overallTokensData_) {\n return getOverallTokensData(listedTokens());\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserSupplyData(\n address user_,\n address token_\n )\n public\n view\n returns (Structs.UserSupplyData memory userSupplyData_, Structs.OverallTokenData memory overallTokenData_)\n {\n overallTokenData_ = getOverallTokenData(token_);\n uint256 userSupply_ = getUserSupply(user_, token_);\n\n if (userSupply_ > 0) {\n // if userSupply_ == 0 -> user not configured yet for token at Liquidity\n userSupplyData_.modeWithInterest = userSupply_ & 1 == 1;\n userSupplyData_.supply = BigMathMinified.fromBigNumber(\n (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n // get updated expanded withdrawal limit\n userSupplyData_.withdrawalLimit = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(\n userSupply_,\n userSupplyData_.supply\n );\n\n userSupplyData_.lastUpdateTimestamp =\n (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) &\n X33;\n userSupplyData_.expandPercent = (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;\n userSupplyData_.expandDuration = (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24;\n userSupplyData_.baseWithdrawalLimit = BigMathMinified.fromBigNumber(\n (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n if (userSupplyData_.modeWithInterest) {\n // convert raw amounts to normal for withInterest mode\n userSupplyData_.supply =\n (userSupplyData_.supply * overallTokenData_.supplyExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n userSupplyData_.withdrawalLimit =\n (userSupplyData_.withdrawalLimit * overallTokenData_.supplyExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n userSupplyData_.baseWithdrawalLimit =\n (userSupplyData_.baseWithdrawalLimit * overallTokenData_.supplyExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n }\n\n userSupplyData_.withdrawableUntilLimit = userSupplyData_.supply > userSupplyData_.withdrawalLimit\n ? userSupplyData_.supply - userSupplyData_.withdrawalLimit\n : 0;\n uint balanceOf_ = token_ == _NATIVE_TOKEN_ADDRESS\n ? address(LIQUIDITY).balance\n : TokenInterface(token_).balanceOf(address(LIQUIDITY));\n if (token_ == WEETH) {\n balanceOf_ += ZIRCUIT.balance(WEETH, address(LIQUIDITY));\n }\n\n userSupplyData_.withdrawable = balanceOf_ > userSupplyData_.withdrawableUntilLimit\n ? userSupplyData_.withdrawableUntilLimit\n : balanceOf_;\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserMultipleSupplyData(\n address user_,\n address[] calldata tokens_\n )\n public\n view\n returns (\n Structs.UserSupplyData[] memory userSuppliesData_,\n Structs.OverallTokenData[] memory overallTokensData_\n )\n {\n uint256 length_ = tokens_.length;\n userSuppliesData_ = new Structs.UserSupplyData[](length_);\n overallTokensData_ = new Structs.OverallTokenData[](length_);\n\n for (uint256 i; i < length_; i++) {\n (userSuppliesData_[i], overallTokensData_[i]) = getUserSupplyData(user_, tokens_[i]);\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserBorrowData(\n address user_,\n address token_\n )\n public\n view\n returns (Structs.UserBorrowData memory userBorrowData_, Structs.OverallTokenData memory overallTokenData_)\n {\n overallTokenData_ = getOverallTokenData(token_);\n uint256 userBorrow_ = getUserBorrow(user_, token_);\n\n if (userBorrow_ > 0) {\n // if userBorrow_ == 0 -> user not configured yet for token at Liquidity\n\n userBorrowData_.modeWithInterest = userBorrow_ & 1 == 1;\n\n userBorrowData_.borrow = BigMathMinified.fromBigNumber(\n (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n // get updated expanded borrow limit\n userBorrowData_.borrowLimit = LiquidityCalcs.calcBorrowLimitBeforeOperate(\n userBorrow_,\n userBorrowData_.borrow\n );\n\n userBorrowData_.lastUpdateTimestamp =\n (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) &\n X33;\n userBorrowData_.expandPercent = (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;\n userBorrowData_.expandDuration = (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24;\n userBorrowData_.baseBorrowLimit = BigMathMinified.fromBigNumber(\n (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n userBorrowData_.maxBorrowLimit = BigMathMinified.fromBigNumber(\n (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n if (userBorrowData_.modeWithInterest) {\n // convert raw amounts to normal for withInterest mode\n userBorrowData_.borrow =\n (userBorrowData_.borrow * overallTokenData_.borrowExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n userBorrowData_.borrowLimit =\n (userBorrowData_.borrowLimit * overallTokenData_.borrowExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n userBorrowData_.baseBorrowLimit =\n (userBorrowData_.baseBorrowLimit * overallTokenData_.borrowExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n userBorrowData_.maxBorrowLimit =\n (userBorrowData_.maxBorrowLimit * overallTokenData_.borrowExchangePrice) /\n EXCHANGE_PRICES_PRECISION;\n }\n\n userBorrowData_.borrowLimitUtilization =\n (overallTokenData_.maxUtilization * overallTokenData_.totalSupply) /\n 1e4;\n\n // uncollected revenue is counting towards available balanceOf.\n // because of this \"borrowable\" would be showing an amount that can go above 100% utilization, causing a revert.\n // need to take into consideration the borrowable amount until the max utilization limit, which depends on the total\n // borrow amount (not user specific)\n uint borrowableUntilUtilizationLimit_ = userBorrowData_.borrowLimitUtilization >\n overallTokenData_.totalBorrow\n ? userBorrowData_.borrowLimitUtilization - overallTokenData_.totalBorrow\n : 0;\n\n uint borrowableUntilBorrowLimit_ = userBorrowData_.borrowLimit > userBorrowData_.borrow\n ? userBorrowData_.borrowLimit - userBorrowData_.borrow\n : 0;\n\n userBorrowData_.borrowableUntilLimit = borrowableUntilBorrowLimit_ > borrowableUntilUtilizationLimit_\n ? borrowableUntilUtilizationLimit_\n : borrowableUntilBorrowLimit_;\n\n // if available balance at Liquidity is less than the borrowableUntilLimit amount, then the balance is\n // the limiting borrowable amount.\n uint balanceOf_ = token_ == _NATIVE_TOKEN_ADDRESS\n ? address(LIQUIDITY).balance\n : TokenInterface(token_).balanceOf(address(LIQUIDITY));\n\n userBorrowData_.borrowable = balanceOf_ > userBorrowData_.borrowableUntilLimit\n ? userBorrowData_.borrowableUntilLimit\n : balanceOf_;\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserMultipleBorrowData(\n address user_,\n address[] calldata tokens_\n )\n public\n view\n returns (\n Structs.UserBorrowData[] memory userBorrowingsData_,\n Structs.OverallTokenData[] memory overallTokensData_\n )\n {\n uint256 length_ = tokens_.length;\n userBorrowingsData_ = new UserBorrowData[](length_);\n overallTokensData_ = new Structs.OverallTokenData[](length_);\n\n for (uint256 i; i < length_; i++) {\n (userBorrowingsData_[i], overallTokensData_[i]) = getUserBorrowData(user_, tokens_[i]);\n }\n }\n\n /// @inheritdoc IFluidLiquidityResolver\n function getUserMultipleBorrowSupplyData(\n address user_,\n address[] calldata supplyTokens_,\n address[] calldata borrowTokens_\n )\n public\n view\n returns (\n Structs.UserSupplyData[] memory userSuppliesData_,\n Structs.OverallTokenData[] memory overallSupplyTokensData_,\n Structs.UserBorrowData[] memory userBorrowingsData_,\n Structs.OverallTokenData[] memory overallBorrowTokensData_\n )\n {\n uint256 length_ = supplyTokens_.length;\n userSuppliesData_ = new Structs.UserSupplyData[](length_);\n overallSupplyTokensData_ = new Structs.OverallTokenData[](length_);\n for (uint256 i; i < length_; i++) {\n (userSuppliesData_[i], overallSupplyTokensData_[i]) = getUserSupplyData(user_, supplyTokens_[i]);\n }\n\n length_ = borrowTokens_.length;\n userBorrowingsData_ = new UserBorrowData[](length_);\n overallBorrowTokensData_ = new Structs.OverallTokenData[](length_);\n for (uint256 i; i < length_; i++) {\n (userBorrowingsData_[i], overallBorrowTokensData_[i]) = getUserBorrowData(user_, borrowTokens_[i]);\n }\n }\n}\n"
},
"contracts/periphery/resolvers/liquidity/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Structs as AdminModuleStructs } from \"../../../liquidity/adminModule/structs.sol\";\n\nabstract contract Structs {\n struct RateData {\n uint256 version;\n AdminModuleStructs.RateDataV1Params rateDataV1;\n AdminModuleStructs.RateDataV2Params rateDataV2;\n }\n\n struct OverallTokenData {\n uint256 borrowRate;\n uint256 supplyRate;\n uint256 fee; // revenue fee\n uint256 lastStoredUtilization;\n uint256 storageUpdateThreshold;\n uint256 lastUpdateTimestamp;\n uint256 supplyExchangePrice;\n uint256 borrowExchangePrice;\n uint256 supplyRawInterest;\n uint256 supplyInterestFree;\n uint256 borrowRawInterest;\n uint256 borrowInterestFree;\n uint256 totalSupply;\n uint256 totalBorrow;\n uint256 revenue;\n uint256 maxUtilization; // maximum allowed utilization\n RateData rateData;\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserSupplyData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 supply; // user supply amount\n // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)\n uint256 withdrawalLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent; // withdrawal limit expand percent in 1e2\n uint256 expandDuration; // withdrawal limit expand duration in seconds\n uint256 baseWithdrawalLimit;\n // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)\n uint256 withdrawableUntilLimit;\n uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserBorrowData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 borrow; // user borrow amount\n uint256 borrowLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent;\n uint256 expandDuration;\n uint256 baseBorrowLimit;\n uint256 maxBorrowLimit;\n uint256 borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)\n uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization\n uint256 borrowLimitUtilization; // borrow limit for `maxUtilization`\n }\n}\n"
},
"contracts/periphery/resolvers/liquidity/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\n\ncontract Variables {\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\n /// validated in the constructor.\n bytes32 internal constant GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\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 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 uint256 internal constant FOUR_DECIMALS = 10000;\n uint256 internal constant X8 = 0xff;\n uint256 internal constant X14 = 0x3fff;\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 /// @notice address of the liquidity contract\n IFluidLiquidity public immutable LIQUIDITY;\n\n constructor(IFluidLiquidity liquidity_) {\n LIQUIDITY = IFluidLiquidity(liquidity_);\n }\n}\n"
},
"contracts/periphery/resolvers/vault/helpers.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"./variables.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { TickMath } from \"../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\n\ncontract Helpers is Variables, Structs {\n function normalSlot(uint256 slot_) public pure returns (bytes32) {\n return bytes32(slot_);\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping\n function calculateStorageSlotUintMapping(uint256 slot_, uint key_) public pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping\n function calculateStorageSlotIntMapping(uint256 slot_, int key_) public pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for double mapping\n function calculateDoubleIntUintMapping(uint256 slot_, int key1_, uint key2_) public pure returns (bytes32) {\n bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n return keccak256(abi.encode(key2_, intermediateSlot_));\n }\n\n function tickHelper(uint tickRaw_) public pure returns (int tick) {\n require(tickRaw_ < X20, \"invalid-number\");\n if (tickRaw_ > 0) {\n tick = tickRaw_ & 1 == 1 ? int((tickRaw_ >> 1) & X19) : -int((tickRaw_ >> 1) & X19);\n } else {\n tick = type(int).min;\n }\n }\n\n constructor(\n address factory_,\n address liquidity_,\n address liquidityResolver_\n ) Variables(factory_, liquidity_, liquidityResolver_) {}\n}\n"
},
"contracts/periphery/resolvers/vault/iVaultResolver.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs } from \"./structs.sol\";\n\ninterface IFluidVaultResolver {\n function vaultByNftId(uint nftId_) external view returns (address vault_);\n\n function positionByNftId(\n uint nftId_\n ) external view returns (Structs.UserPosition memory userPosition_, Structs.VaultEntireData memory vaultData_);\n\n function getVaultVariablesRaw(address vault_) external view returns (uint);\n\n function getVaultVariables2Raw(address vault_) external view returns (uint);\n\n function getTickHasDebtRaw(address vault_, int key_) external view returns (uint);\n\n function getTickDataRaw(address vault_, int tick_) external view returns (uint);\n\n function getBranchDataRaw(address vault_, uint branch_) external view returns (uint);\n\n function getAllVaultsAddresses() external view returns (address[] memory vaults_);\n\n function getVaultLiquidation(\n address vault_,\n uint tokenInAmt_\n ) external returns (Structs.LiquidationStruct memory liquidationData_);\n\n function getVaultEntireData(address vault_) external view returns (Structs.VaultEntireData memory vaultData_);\n}\n"
},
"contracts/periphery/resolvers/vault/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Helpers } from \"./helpers.sol\";\nimport { TickMath } from \"../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { IFluidOracle } from \"../../../oracle/fluidOracle.sol\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { Structs as FluidLiquidityResolverStructs } from \"../liquidity/structs.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { LiquidityCalcs } from \"../../../libraries/liquidityCalcs.sol\";\n\ninterface TokenInterface {\n function balanceOf(address) external view returns (uint);\n}\n\ninterface IZtakingPool {\n function balance(address token_, address staker_) external view returns (uint256);\n}\n\n/// @notice Fluid Vault protocol resolver\n/// Implements various view-only methods to give easy access to Vault protocol data.\ncontract FluidVaultResolver is Helpers {\n constructor(\n address factory_,\n address liquidity_,\n address liquidityResolver_\n ) Helpers(factory_, liquidity_, liquidityResolver_) {}\n\n function getVaultAddress(uint256 vaultId_) public view returns (address vault_) {\n // @dev based on https://ethereum.stackexchange.com/a/61413\n bytes memory data;\n if (vaultId_ == 0x00) {\n // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment\n return address(0);\n } else if (vaultId_ <= 0x7f) {\n data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), address(FACTORY), uint8(vaultId_));\n } else if (vaultId_ <= 0xff) {\n data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), address(FACTORY), bytes1(0x81), uint8(vaultId_));\n } else if (vaultId_ <= 0xffff) {\n data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), address(FACTORY), bytes1(0x82), uint16(vaultId_));\n } else if (vaultId_ <= 0xffffff) {\n data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), address(FACTORY), bytes1(0x83), uint24(vaultId_));\n } else {\n data = abi.encodePacked(bytes1(0xda), bytes1(0x94), address(FACTORY), bytes1(0x84), uint32(vaultId_));\n }\n\n return address(uint160(uint256(keccak256(data))));\n }\n\n function getVaultId(address vault_) public view returns (uint id_) {\n id_ = IFluidVaultT1(vault_).VAULT_ID();\n }\n\n function getTokenConfig(uint nftId_) public view returns (uint) {\n return FACTORY.readFromStorage(calculateStorageSlotUintMapping(3, nftId_));\n }\n\n function getVaultVariablesRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(0));\n }\n\n function getVaultVariables2Raw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(1));\n }\n\n function getAbsorbedLiquidityRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(2));\n }\n\n function getPositionDataRaw(address vault_, uint positionId_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotUintMapping(3, positionId_));\n }\n\n // if tick > 0 then key_ = tick / 256\n // if tick < 0 then key_ = (tick / 256) - 1\n function getTickHasDebtRaw(address vault_, int key_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotIntMapping(4, key_));\n }\n\n function getTickDataRaw(address vault_, int tick_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotIntMapping(5, tick_));\n }\n\n // TODO: Verify below\n // id_ = (realId_ / 3) + 1\n function getTickIdDataRaw(address vault_, int tick_, uint id_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateDoubleIntUintMapping(6, tick_, id_));\n }\n\n function getBranchDataRaw(address vault_, uint branch_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotUintMapping(7, branch_));\n }\n\n function getRateRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(8));\n }\n\n function getRebalancer(address vault_) public view returns (address) {\n return address(uint160(IFluidVaultT1(vault_).readFromStorage(normalSlot(9))));\n }\n\n function getTotalVaults() public view returns (uint) {\n return FACTORY.totalVaults();\n }\n\n function getAllVaultsAddresses() public view returns (address[] memory vaults_) {\n uint totalVaults_ = getTotalVaults();\n vaults_ = new address[](totalVaults_);\n for (uint i = 0; i < totalVaults_; i++) {\n vaults_[i] = getVaultAddress((i + 1));\n }\n }\n\n function _getVaultConstants(address vault_) internal view returns (IFluidVaultT1.ConstantViews memory constants_) {\n constants_ = IFluidVaultT1(vault_).constantsView();\n }\n\n function _getVaultConfig(address vault_) internal view returns (Configs memory configs_) {\n uint vaultVariables2_ = getVaultVariables2Raw(vault_);\n configs_.supplyRateMagnifier = uint16(vaultVariables2_ & X16);\n configs_.borrowRateMagnifier = uint16((vaultVariables2_ >> 16) & X16);\n configs_.collateralFactor = (uint16((vaultVariables2_ >> 32) & X10)) * 10;\n configs_.liquidationThreshold = (uint16((vaultVariables2_ >> 42) & X10)) * 10;\n configs_.liquidationMaxLimit = (uint16((vaultVariables2_ >> 52) & X10) * 10);\n configs_.withdrawalGap = uint16((vaultVariables2_ >> 62) & X10) * 10;\n configs_.liquidationPenalty = uint16((vaultVariables2_ >> 72) & X10);\n configs_.borrowFee = uint16((vaultVariables2_ >> 82) & X10);\n configs_.oracle = address(uint160(vaultVariables2_ >> 96));\n if (configs_.oracle != address(0)) {\n try IFluidOracle(configs_.oracle).getExchangeRateOperate() returns (uint256 exchangeRate_) {\n configs_.oraclePriceOperate = exchangeRate_;\n configs_.oraclePriceLiquidate = IFluidOracle(configs_.oracle).getExchangeRateLiquidate();\n } catch {\n // deprecated backward compatible for older vaults oracles\n configs_.oraclePriceOperate = IFluidOracle(configs_.oracle).getExchangeRate();\n configs_.oraclePriceLiquidate = configs_.oraclePriceOperate;\n }\n }\n configs_.rebalancer = getRebalancer(vault_);\n }\n\n function _getExchangePricesAndRates(\n address vault_,\n Configs memory configs_,\n FluidLiquidityResolverStructs.OverallTokenData memory liquiditySupplytokenData_,\n FluidLiquidityResolverStructs.OverallTokenData memory liquidityBorrowtokenData_\n ) internal view returns (ExchangePricesAndRates memory exchangePricesAndRates_) {\n uint exchangePrices_ = getRateRaw(vault_);\n exchangePricesAndRates_.lastStoredLiquiditySupplyExchangePrice = exchangePrices_ & X64;\n exchangePricesAndRates_.lastStoredLiquidityBorrowExchangePrice = (exchangePrices_ >> 64) & X64;\n exchangePricesAndRates_.lastStoredVaultSupplyExchangePrice = (exchangePrices_ >> 128) & X64;\n exchangePricesAndRates_.lastStoredVaultBorrowExchangePrice = (exchangePrices_ >> 192) & X64;\n\n (\n exchangePricesAndRates_.liquiditySupplyExchangePrice,\n exchangePricesAndRates_.liquidityBorrowExchangePrice,\n exchangePricesAndRates_.vaultSupplyExchangePrice,\n exchangePricesAndRates_.vaultBorrowExchangePrice\n ) = IFluidVaultT1(vault_).updateExchangePrices(getVaultVariables2Raw(vault_));\n\n exchangePricesAndRates_.supplyRateLiquidity = liquiditySupplytokenData_.supplyRate;\n exchangePricesAndRates_.borrowRateLiquidity = liquidityBorrowtokenData_.borrowRate;\n exchangePricesAndRates_.supplyRateVault =\n (liquiditySupplytokenData_.supplyRate * configs_.supplyRateMagnifier) /\n 10000;\n exchangePricesAndRates_.borrowRateVault =\n (liquidityBorrowtokenData_.borrowRate * configs_.borrowRateMagnifier) /\n 10000;\n exchangePricesAndRates_.rewardsRate = configs_.supplyRateMagnifier > 10000\n ? configs_.supplyRateMagnifier - 10000\n : 0;\n }\n\n function _getTotalSupplyAndBorrow(\n address vault_,\n ExchangePricesAndRates memory exchangePricesAndRates_,\n IFluidVaultT1.ConstantViews memory constantsVariables_\n ) internal view returns (TotalSupplyAndBorrow memory totalSupplyAndBorrow_) {\n uint vaultVariables_ = getVaultVariablesRaw(vault_);\n uint absorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);\n uint totalSupplyLiquidity_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserSupplySlot);\n // extracting user's supply\n totalSupplyLiquidity_ = (totalSupplyLiquidity_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\n // converting big number into normal number\n totalSupplyLiquidity_ = (totalSupplyLiquidity_ >> 8) << (totalSupplyLiquidity_ & X8);\n uint totalBorrowLiquidity_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserBorrowSlot);\n // extracting user's borrow\n totalBorrowLiquidity_ = (totalBorrowLiquidity_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\n // converting big number into normal number\n totalBorrowLiquidity_ = (totalBorrowLiquidity_ >> 8) << (totalBorrowLiquidity_ & X8);\n\n totalSupplyAndBorrow_.totalSupplyVault = (vaultVariables_ >> 82) & X64;\n // Converting bignumber into normal number\n totalSupplyAndBorrow_.totalSupplyVault =\n (totalSupplyAndBorrow_.totalSupplyVault >> 8) <<\n (totalSupplyAndBorrow_.totalSupplyVault & X8);\n totalSupplyAndBorrow_.totalBorrowVault = (vaultVariables_ >> 146) & X64;\n // Converting bignumber into normal number\n totalSupplyAndBorrow_.totalBorrowVault =\n (totalSupplyAndBorrow_.totalBorrowVault >> 8) <<\n (totalSupplyAndBorrow_.totalBorrowVault & X8);\n\n totalSupplyAndBorrow_.totalSupplyLiquidity = totalSupplyLiquidity_;\n totalSupplyAndBorrow_.totalBorrowLiquidity = totalBorrowLiquidity_;\n\n totalSupplyAndBorrow_.absorbedBorrow = absorbedLiquidity_ & X128;\n totalSupplyAndBorrow_.absorbedSupply = absorbedLiquidity_ >> 128;\n\n // converting raw total supply & total borrow into normal amounts\n totalSupplyAndBorrow_.totalSupplyVault =\n (totalSupplyAndBorrow_.totalSupplyVault * exchangePricesAndRates_.vaultSupplyExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalBorrowVault =\n (totalSupplyAndBorrow_.totalBorrowVault * exchangePricesAndRates_.vaultBorrowExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalSupplyLiquidity =\n (totalSupplyAndBorrow_.totalSupplyLiquidity * exchangePricesAndRates_.liquiditySupplyExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalBorrowLiquidity =\n (totalSupplyAndBorrow_.totalBorrowLiquidity * exchangePricesAndRates_.liquidityBorrowExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.absorbedSupply =\n (totalSupplyAndBorrow_.absorbedSupply * exchangePricesAndRates_.vaultSupplyExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.absorbedBorrow =\n (totalSupplyAndBorrow_.absorbedBorrow * exchangePricesAndRates_.vaultBorrowExchangePrice) /\n 1e12;\n }\n\n address private constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;\n IZtakingPool private constant ZIRCUIT = IZtakingPool(0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6);\n\n function _getLimitsAndAvailability(\n TotalSupplyAndBorrow memory totalSupplyAndBorrow_,\n ExchangePricesAndRates memory exchangePricesAndRates_,\n IFluidVaultT1.ConstantViews memory constantsVariables_,\n Configs memory configs_,\n FluidLiquidityResolverStructs.UserBorrowData memory liquidityBorrowtokenData_\n ) internal view returns (LimitsAndAvailability memory limitsAndAvailability_) {\n // fetching user's supply slot data\n uint userSupplyLiquidityData_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserSupplySlot);\n if (userSupplyLiquidityData_ > 0) {\n // converting current user's supply from big number to normal\n uint userSupply_ = (userSupplyLiquidityData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\n userSupply_ = (userSupply_ >> 8) << (userSupply_ & X8);\n\n // fetching liquidity's withdrawal limit\n uint supplyLimitRaw_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(\n userSupplyLiquidityData_,\n userSupply_\n );\n\n limitsAndAvailability_.withdrawLimit =\n (supplyLimitRaw_ * exchangePricesAndRates_.liquiditySupplyExchangePrice) /\n 1e12;\n\n limitsAndAvailability_.withdrawableUntilLimit = totalSupplyAndBorrow_.totalSupplyLiquidity >\n limitsAndAvailability_.withdrawLimit\n ? totalSupplyAndBorrow_.totalSupplyLiquidity - limitsAndAvailability_.withdrawLimit\n : 0;\n uint withdrawalGap_ = (totalSupplyAndBorrow_.totalSupplyLiquidity * configs_.withdrawalGap) / 1e4;\n limitsAndAvailability_.withdrawableUntilLimit = (limitsAndAvailability_.withdrawableUntilLimit >\n withdrawalGap_)\n ? (((limitsAndAvailability_.withdrawableUntilLimit - withdrawalGap_) * 999999) / 1000000)\n : 0;\n\n uint balanceOf_;\n if (constantsVariables_.supplyToken == NATIVE_TOKEN_ADDRESS) {\n balanceOf_ = address(LIQUIDITY).balance;\n } else {\n balanceOf_ = TokenInterface(constantsVariables_.supplyToken).balanceOf(address(LIQUIDITY));\n }\n if (constantsVariables_.supplyToken == WEETH) {\n balanceOf_ += ZIRCUIT.balance(WEETH, address(LIQUIDITY));\n }\n limitsAndAvailability_.withdrawable = balanceOf_ > limitsAndAvailability_.withdrawableUntilLimit\n ? limitsAndAvailability_.withdrawableUntilLimit\n : balanceOf_;\n }\n\n uint userBorrowLiquidityData_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserBorrowSlot);\n if (userBorrowLiquidityData_ > 0) {\n // converting current user's supply from big number to normal\n uint userBorrow_ = (userBorrowLiquidityData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\n userBorrow_ = (userBorrow_ >> 8) << (userBorrow_ & X8);\n\n limitsAndAvailability_.borrowLimit = liquidityBorrowtokenData_.borrowLimit;\n limitsAndAvailability_.borrowLimitUtilization = liquidityBorrowtokenData_.borrowLimitUtilization;\n limitsAndAvailability_.borrowableUntilLimit =\n (liquidityBorrowtokenData_.borrowableUntilLimit * 999999) /\n 1000000;\n\n uint balanceOf_;\n if (constantsVariables_.borrowToken == NATIVE_TOKEN_ADDRESS) {\n balanceOf_ = address(LIQUIDITY).balance;\n } else {\n balanceOf_ = TokenInterface(constantsVariables_.borrowToken).balanceOf(address(LIQUIDITY));\n }\n limitsAndAvailability_.borrowable = balanceOf_ > limitsAndAvailability_.borrowableUntilLimit\n ? limitsAndAvailability_.borrowableUntilLimit\n : balanceOf_;\n }\n\n limitsAndAvailability_.minimumBorrowing = (10001 * exchangePricesAndRates_.vaultBorrowExchangePrice) / 1e12;\n }\n\n function getVaultState(address vault_) public view returns (VaultState memory vaultState_) {\n uint vaultVariables_ = getVaultVariablesRaw(vault_);\n\n vaultState_.topTick = tickHelper(((vaultVariables_ >> 2) & X20));\n vaultState_.currentBranch = (vaultVariables_ >> 22) & X30;\n vaultState_.totalBranch = (vaultVariables_ >> 52) & X30;\n vaultState_.totalSupply = BigMathMinified.fromBigNumber((vaultVariables_ >> 82) & X64, 8, X8);\n vaultState_.totalBorrow = BigMathMinified.fromBigNumber((vaultVariables_ >> 146) & X64, 8, X8);\n vaultState_.totalPositions = (vaultVariables_ >> 210) & X32;\n\n uint currentBranchData_ = getBranchDataRaw(vault_, vaultState_.currentBranch);\n vaultState_.currentBranchState.status = currentBranchData_ & 3;\n vaultState_.currentBranchState.minimaTick = tickHelper(((currentBranchData_ >> 2) & X20));\n vaultState_.currentBranchState.debtFactor = (currentBranchData_ >> 116) & X50;\n vaultState_.currentBranchState.partials = (currentBranchData_ >> 22) & X30;\n vaultState_.currentBranchState.debtLiquidity = BigMathMinified.fromBigNumber(\n (currentBranchData_ >> 52) & X64,\n 8,\n X8\n );\n vaultState_.currentBranchState.baseBranchId = (currentBranchData_ >> 166) & X30;\n vaultState_.currentBranchState.baseBranchMinima = tickHelper(((currentBranchData_ >> 196) & X20));\n }\n\n function getVaultEntireData(address vault_) public view returns (VaultEntireData memory vaultData_) {\n vaultData_.vault = vault_;\n vaultData_.constantVariables = _getVaultConstants(vault_);\n\n (\n FluidLiquidityResolverStructs.UserSupplyData memory liquidityUserSupplyData_,\n FluidLiquidityResolverStructs.OverallTokenData memory liquiditySupplyTokenData_\n ) = LIQUIDITY_RESOLVER.getUserSupplyData(vault_, vaultData_.constantVariables.supplyToken);\n\n (\n FluidLiquidityResolverStructs.UserBorrowData memory liquidityUserBorrowData_,\n FluidLiquidityResolverStructs.OverallTokenData memory liquidityBorrowTokenData_\n ) = LIQUIDITY_RESOLVER.getUserBorrowData(vault_, vaultData_.constantVariables.borrowToken);\n\n vaultData_.configs = _getVaultConfig(vault_);\n vaultData_.exchangePricesAndRates = _getExchangePricesAndRates(\n vault_,\n vaultData_.configs,\n liquiditySupplyTokenData_,\n liquidityBorrowTokenData_\n );\n vaultData_.totalSupplyAndBorrow = _getTotalSupplyAndBorrow(\n vault_,\n vaultData_.exchangePricesAndRates,\n vaultData_.constantVariables\n );\n vaultData_.limitsAndAvailability = _getLimitsAndAvailability(\n vaultData_.totalSupplyAndBorrow,\n vaultData_.exchangePricesAndRates,\n vaultData_.constantVariables,\n vaultData_.configs,\n liquidityUserBorrowData_\n );\n vaultData_.vaultState = getVaultState(vault_);\n\n vaultData_.liquidityUserSupplyData = liquidityUserSupplyData_;\n vaultData_.liquidityUserBorrowData = liquidityUserBorrowData_;\n }\n\n function getVaultsEntireData(\n address[] memory vaults_\n ) external view returns (VaultEntireData[] memory vaultsData_) {\n uint length_ = vaults_.length;\n vaultsData_ = new VaultEntireData[](length_);\n for (uint i = 0; i < length_; i++) {\n vaultsData_[i] = getVaultEntireData(vaults_[i]);\n }\n }\n\n function getVaultsEntireData() external view returns (VaultEntireData[] memory vaultsData_) {\n address[] memory vaults_ = getAllVaultsAddresses();\n uint length_ = vaults_.length;\n vaultsData_ = new VaultEntireData[](length_);\n for (uint i = 0; i < length_; i++) {\n vaultsData_[i] = getVaultEntireData(vaults_[i]);\n }\n }\n\n function positionByNftId(\n uint nftId_\n ) public view returns (UserPosition memory userPosition_, VaultEntireData memory vaultData_) {\n userPosition_.nftId = nftId_;\n address vault_ = vaultByNftId(nftId_);\n if (vault_ != address(0)) {\n uint positionData_ = getPositionDataRaw(vault_, nftId_);\n vaultData_ = getVaultEntireData(vault_);\n\n userPosition_.owner = FACTORY.ownerOf(nftId_);\n userPosition_.isSupplyPosition = (positionData_ & 1) == 1;\n userPosition_.supply = (positionData_ >> 45) & X64;\n // Converting big number into normal number\n userPosition_.supply = (userPosition_.supply >> 8) << (userPosition_.supply & X8);\n userPosition_.beforeSupply = userPosition_.supply;\n userPosition_.dustBorrow = (positionData_ >> 109) & X64;\n // Converting big number into normal number\n userPosition_.dustBorrow = (userPosition_.dustBorrow >> 8) << (userPosition_.dustBorrow & X8);\n userPosition_.beforeDustBorrow = userPosition_.dustBorrow;\n if (!userPosition_.isSupplyPosition) {\n userPosition_.tick = (positionData_ & 2) == 2\n ? int((positionData_ >> 2) & X19)\n : -int((positionData_ >> 2) & X19);\n userPosition_.tickId = (positionData_ >> 21) & X24;\n userPosition_.borrow =\n (TickMath.getRatioAtTick(int24(userPosition_.tick)) * userPosition_.supply) >>\n 96;\n userPosition_.beforeBorrow = userPosition_.borrow - userPosition_.beforeDustBorrow;\n\n uint tickData_ = getTickDataRaw(vault_, userPosition_.tick);\n\n if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > userPosition_.tickId)) {\n // user got liquidated\n userPosition_.isLiquidated = true;\n (userPosition_.tick, userPosition_.borrow, userPosition_.supply, , ) = IFluidVaultT1(vault_)\n .fetchLatestPosition(userPosition_.tick, userPosition_.tickId, userPosition_.borrow, tickData_);\n }\n\n if (userPosition_.borrow > userPosition_.dustBorrow) {\n userPosition_.borrow = userPosition_.borrow - userPosition_.dustBorrow;\n } else {\n // TODO: Make sure this is right. If borrow is less than dust debt then both gets 0\n userPosition_.borrow = 0;\n userPosition_.dustBorrow = 0;\n }\n }\n\n // converting raw amounts into normal\n userPosition_.beforeSupply =\n (userPosition_.beforeSupply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /\n 1e12;\n userPosition_.beforeBorrow =\n (userPosition_.beforeBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.beforeDustBorrow =\n (userPosition_.beforeDustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.supply =\n (userPosition_.supply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /\n 1e12;\n userPosition_.borrow =\n (userPosition_.borrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.dustBorrow =\n (userPosition_.dustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n }\n }\n\n function positionsNftIdOfUser(address user_) public view returns (uint[] memory nftIds_) {\n uint totalPositions_ = FACTORY.balanceOf(user_);\n nftIds_ = new uint[](totalPositions_);\n for (uint i; i < totalPositions_; i++) {\n nftIds_[i] = FACTORY.tokenOfOwnerByIndex(user_, i);\n }\n }\n\n function vaultByNftId(uint nftId_) public view returns (address vault_) {\n uint tokenConfig_ = getTokenConfig(nftId_);\n vault_ = FACTORY.getVaultAddress((tokenConfig_ >> 192) & X32);\n }\n\n function positionsByUser(\n address user_\n ) external view returns (UserPosition[] memory userPositions_, VaultEntireData[] memory vaultsData_) {\n uint[] memory nftIds_ = positionsNftIdOfUser(user_);\n uint length_ = nftIds_.length;\n userPositions_ = new UserPosition[](length_);\n vaultsData_ = new VaultEntireData[](length_);\n for (uint i = 0; i < length_; i++) {\n (userPositions_[i], vaultsData_[i]) = positionByNftId(nftIds_[i]);\n }\n }\n\n function totalPositions() external view returns (uint) {\n return FACTORY.totalSupply();\n }\n\n /// @dev fetches available liquidations\n /// @param vault_ address of vault for which to fetch\n /// @param tokenInAmt_ token in aka debt to payback, leave 0 to get max\n /// @return liquidationData_ liquidation related data. Check out structs.sol\n function getVaultLiquidation(\n address vault_,\n uint tokenInAmt_\n ) public returns (LiquidationStruct memory liquidationData_) {\n liquidationData_.vault = vault_;\n IFluidVaultT1.ConstantViews memory constants_ = _getVaultConstants(vault_);\n liquidationData_.tokenIn = constants_.borrowToken;\n liquidationData_.tokenOut = constants_.supplyToken;\n\n uint amtOut_;\n uint amtIn_;\n\n tokenInAmt_ = tokenInAmt_ == 0 ? X128 : tokenInAmt_;\n // running without absorb\n try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, false) {\n // Handle successful execution\n } catch Error(string memory) {\n // Handle generic errors with a reason\n } catch (bytes memory lowLevelData_) {\n // Check if the error data is long enough to contain a selector\n if (lowLevelData_.length >= 68) {\n bytes4 errorSelector_;\n assembly {\n // Extract the selector from the error data\n errorSelector_ := mload(add(lowLevelData_, 0x20))\n }\n if (errorSelector_ == IFluidVaultT1.FluidLiquidateResult.selector) {\n assembly {\n amtOut_ := mload(add(lowLevelData_, 36))\n amtIn_ := mload(add(lowLevelData_, 68))\n }\n liquidationData_.tokenOutAmtOne = amtOut_;\n liquidationData_.tokenInAmtOne = amtIn_;\n } else {\n // tokenInAmtOne & tokenOutAmtOne remains 0\n }\n }\n }\n\n // running with absorb\n try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, true) {\n // Handle successful execution\n } catch Error(string memory) {\n // Handle generic errors with a reason\n } catch (bytes memory lowLevelData_) {\n // Check if the error data is long enough to contain a selector\n if (lowLevelData_.length >= 68) {\n bytes4 errorSelector_;\n assembly {\n // Extract the selector from the error data\n errorSelector_ := mload(add(lowLevelData_, 0x20))\n }\n if (errorSelector_ == IFluidVaultT1.FluidLiquidateResult.selector) {\n assembly {\n amtOut_ := mload(add(lowLevelData_, 36))\n amtIn_ := mload(add(lowLevelData_, 68))\n }\n liquidationData_.tokenOutAmtTwo = amtOut_;\n liquidationData_.tokenInAmtTwo = amtIn_;\n } else {\n // tokenInAmtTwo & tokenOutAmtTwo remains 0\n }\n }\n }\n }\n\n function getMultipleVaultsLiquidation(\n address[] memory vaults_,\n uint[] memory tokensInAmt_\n ) external returns (LiquidationStruct[] memory liquidationsData_) {\n uint length_ = vaults_.length;\n liquidationsData_ = new LiquidationStruct[](length_);\n for (uint i = 0; i < length_; i++) {\n liquidationsData_[i] = getVaultLiquidation(vaults_[i], tokensInAmt_[i]);\n }\n }\n\n function getAllVaultsLiquidation() external returns (LiquidationStruct[] memory liquidationsData_) {\n address[] memory vaults_ = getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n liquidationsData_ = new LiquidationStruct[](length_);\n for (uint i = 0; i < length_; i++) {\n liquidationsData_[i] = getVaultLiquidation(vaults_[i], 0);\n }\n }\n\n function getVaultAbsorb(address vault_) public returns (AbsorbStruct memory absorbData_) {\n absorbData_.vault = vault_;\n uint absorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);\n try IFluidVaultT1(vault_).absorb() {\n // Handle successful execution\n uint newAbsorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);\n if (newAbsorbedLiquidity_ != absorbedLiquidity_) {\n absorbData_.absorbAvailable = true;\n }\n } catch Error(string memory) {} catch (bytes memory) {}\n }\n\n function getVaultsAbsorb(address[] memory vaults_) public returns (AbsorbStruct[] memory absorbData_) {\n uint length_ = vaults_.length;\n absorbData_ = new AbsorbStruct[](length_);\n for (uint i = 0; i < length_; i++) {\n absorbData_[i] = getVaultAbsorb(vaults_[i]);\n }\n }\n\n function getVaultsAbsorb() public returns (AbsorbStruct[] memory absorbData_) {\n return getVaultsAbsorb(getAllVaultsAddresses());\n }\n}\n"
},
"contracts/periphery/resolvers/vault/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { Structs as FluidLiquidityResolverStructs } from \"../liquidity/structs.sol\";\n\ncontract Structs {\n struct Configs {\n uint16 supplyRateMagnifier;\n uint16 borrowRateMagnifier;\n uint16 collateralFactor;\n uint16 liquidationThreshold;\n uint16 liquidationMaxLimit;\n uint16 withdrawalGap;\n uint16 liquidationPenalty;\n uint16 borrowFee;\n address oracle;\n uint oraclePriceOperate;\n uint oraclePriceLiquidate;\n address rebalancer;\n }\n\n struct ExchangePricesAndRates {\n uint lastStoredLiquiditySupplyExchangePrice;\n uint lastStoredLiquidityBorrowExchangePrice;\n uint lastStoredVaultSupplyExchangePrice;\n uint lastStoredVaultBorrowExchangePrice;\n uint liquiditySupplyExchangePrice;\n uint liquidityBorrowExchangePrice;\n uint vaultSupplyExchangePrice;\n uint vaultBorrowExchangePrice;\n uint supplyRateVault;\n uint borrowRateVault;\n uint supplyRateLiquidity;\n uint borrowRateLiquidity;\n uint rewardsRate; // rewards rate in percent 1e2 precision (1% = 100, 100% = 10000)\n }\n\n struct TotalSupplyAndBorrow {\n uint totalSupplyVault;\n uint totalBorrowVault;\n uint totalSupplyLiquidity;\n uint totalBorrowLiquidity;\n uint absorbedSupply;\n uint absorbedBorrow;\n }\n\n struct LimitsAndAvailability {\n uint withdrawLimit;\n uint withdrawableUntilLimit;\n uint withdrawable;\n uint borrowLimit;\n uint borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)\n uint borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization\n uint borrowLimitUtilization; // borrow limit for `maxUtilization` config at Liquidity\n uint minimumBorrowing;\n }\n\n struct CurrentBranchState {\n uint status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed\n int minimaTick;\n uint debtFactor;\n uint partials;\n uint debtLiquidity;\n uint baseBranchId;\n int baseBranchMinima;\n }\n\n struct VaultState {\n uint totalPositions;\n int topTick;\n uint currentBranch;\n uint totalBranch;\n uint totalBorrow;\n uint totalSupply;\n CurrentBranchState currentBranchState;\n }\n\n struct VaultEntireData {\n address vault;\n IFluidVaultT1.ConstantViews constantVariables;\n Configs configs;\n ExchangePricesAndRates exchangePricesAndRates;\n TotalSupplyAndBorrow totalSupplyAndBorrow;\n LimitsAndAvailability limitsAndAvailability;\n VaultState vaultState;\n // liquidity related data such as supply amount, limits, expansion etc.\n FluidLiquidityResolverStructs.UserSupplyData liquidityUserSupplyData;\n // liquidity related data such as borrow amount, limits, expansion etc.\n FluidLiquidityResolverStructs.UserBorrowData liquidityUserBorrowData;\n }\n\n struct UserPosition {\n uint nftId;\n address owner;\n bool isLiquidated;\n bool isSupplyPosition; // if true that means borrowing is 0\n int tick;\n uint tickId;\n uint beforeSupply;\n uint beforeBorrow;\n uint beforeDustBorrow;\n uint supply;\n uint borrow;\n uint dustBorrow;\n }\n\n /// @dev liquidation related data\n /// @param vault address of vault\n /// @param tokenIn_ address of token in\n /// @param tokenOut_ address of token out\n /// @param tokenInAmtOne_ (without absorb liquidity) minimum of available liquidation & tokenInAmt_\n /// @param tokenOutAmtOne_ (without absorb liquidity) expected token out, collateral to withdraw\n /// @param tokenInAmtTwo_ (absorb liquidity included) minimum of available liquidation & tokenInAmt_. In most cases it'll be same as tokenInAmtOne_ but sometimes can be bigger.\n /// @param tokenOutAmtTwo_ (absorb liquidity included) expected token out, collateral to withdraw. In most cases it'll be same as tokenOutAmtOne_ but sometimes can be bigger.\n /// @dev Liquidity in Two will always be >= One. Sometimes One can provide better swaps, sometimes Two can provide better swaps. But available in Two will always be >= One\n struct LiquidationStruct {\n address vault;\n address tokenIn;\n address tokenOut;\n uint tokenInAmtOne;\n uint tokenOutAmtOne;\n uint tokenInAmtTwo;\n uint tokenOutAmtTwo;\n }\n\n struct AbsorbStruct {\n address vault;\n bool absorbAvailable;\n }\n}\n"
},
"contracts/periphery/resolvers/vault/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidityResolver } from \"../liquidity/iLiquidityResolver.sol\";\nimport { IFluidVaultFactory } from \"../../../protocols/vault/interfaces/iVaultFactory.sol\";\n\ninterface IFluidLiquidity {\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n\ncontract Variables {\n IFluidVaultFactory public immutable FACTORY;\n IFluidLiquidity public immutable LIQUIDITY;\n IFluidLiquidityResolver public immutable LIQUIDITY_RESOLVER;\n\n // 30 bits (used for partials mainly)\n uint internal constant X8 = 0xff;\n uint internal constant X10 = 0x3ff;\n uint internal constant X14 = 0x3fff;\n uint internal constant X15 = 0x7fff;\n uint internal constant X16 = 0xffff;\n uint internal constant X19 = 0x7ffff;\n uint internal constant X20 = 0xfffff;\n uint internal constant X24 = 0xffffff;\n uint internal constant X25 = 0x1ffffff;\n uint internal constant X30 = 0x3fffffff;\n uint internal constant X32 = 0xffffffff;\n uint internal constant X35 = 0x7ffffffff;\n uint internal constant X40 = 0xffffffffff;\n uint internal constant X50 = 0x3ffffffffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n uint internal constant X96 = 0xffffffffffffffffffffffff;\n uint internal constant X128 = 0xffffffffffffffffffffffffffffffff;\n /// @dev address that is mapped to the chain native token\n address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n constructor(address factory_, address liquidity_, address liquidityResolver_) {\n FACTORY = IFluidVaultFactory(factory_);\n LIQUIDITY = IFluidLiquidity(liquidity_);\n LIQUIDITY_RESOLVER = IFluidLiquidityResolver(liquidityResolver_);\n }\n}\n"
},
"contracts/periphery/resolvers/vaultTicksBranches/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { TickMath } from \"../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\n\nimport { Structs } from \"./structs.sol\";\nimport { Variables } from \"./variables.sol\";\n\n/// @notice Fluid Vault protocol ticks & branches resolver\ncontract FluidVaultTicksBranchesResolver is Variables, Structs {\n /// @notice thrown if an input param address is zero\n error FluidVaultTicksBranchesResolver__AddressZero();\n\n /// @notice constructor sets the immutable vault resolver address\n constructor(IFluidVaultResolver vaultResolver_) Variables(vaultResolver_) {\n if (address(vaultResolver_) == address(0)) {\n revert FluidVaultTicksBranchesResolver__AddressZero();\n }\n }\n\n function getTicksDebt(\n address vault_,\n int fromTick_,\n uint totalTicks_\n ) public view returns (TickDebt[] memory ticksDebt_, int toTick_) {\n int topTick_ = _tickHelper(((VAULT_RESOLVER.getVaultVariablesRaw(vault_) >> 2) & X20));\n\n fromTick_ = topTick_ < fromTick_ ? topTick_ : fromTick_;\n if (fromTick_ > type(int).min) {\n // if fromTick_ == tpye(int).min means top tick is not set, meaning no positions exist\n int startMapId_ = fromTick_ < 0 ? ((fromTick_ + 1) / 256) - 1 : fromTick_ / 256;\n // Removing all other after fromTick\n uint tickHasDebt_;\n {\n uint tickHasDebtRaw_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, startMapId_);\n\n uint bitsToRemove_ = uint(-fromTick_ + (startMapId_ * 256 + 255));\n tickHasDebt_ = (tickHasDebtRaw_ << bitsToRemove_) >> bitsToRemove_;\n }\n\n // Adding 1 here as toTick_ is inclusive in the data so if totalTicks_ = 400 then it'll only check 400\n toTick_ = fromTick_ - int(totalTicks_) + 1;\n\n uint count_ = _countTicksWithDebt(vault_, toTick_, startMapId_, tickHasDebt_);\n\n (, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\n ticksDebt_ = _populateTicksDebt(\n vault_,\n toTick_,\n startMapId_,\n tickHasDebt_,\n count_,\n vaultSupplyExchangePrice_,\n vaultBorrowExchangePrice_\n );\n }\n }\n\n function getMultipleVaultsTicksDebt(\n address[] memory vaults_,\n int[] memory fromTicks_,\n uint[] memory totalTicks_\n ) public view returns (VaultsTickDebt[] memory vaultsTickDebt_) {\n uint length_ = vaults_.length;\n\n vaultsTickDebt_ = new VaultsTickDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n (vaultsTickDebt_[i].tickDebt, vaultsTickDebt_[i].toTick) = getTicksDebt(\n vaults_[i],\n fromTicks_[i],\n totalTicks_[i]\n );\n }\n }\n\n function getAllVaultsTicksDebt(uint totalTicks_) public view returns (VaultsTickDebt[] memory vaultsTickDebt_) {\n address[] memory vaults_ = VAULT_RESOLVER.getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n vaultsTickDebt_ = new VaultsTickDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n (vaultsTickDebt_[i].tickDebt, vaultsTickDebt_[i].toTick) = getTicksDebt(\n vaults_[i],\n type(int).max,\n totalTicks_\n );\n }\n }\n\n function getBranchesDebt(\n address vault_,\n uint fromBranchId_,\n uint toBranchId_\n ) public view returns (BranchDebt[] memory branchesDebt_) {\n uint vaultVariables_ = VAULT_RESOLVER.getVaultVariablesRaw(vault_);\n uint totalBranch_ = (vaultVariables_ >> 52) & X30;\n toBranchId_ = (toBranchId_ == 0 ? 1 : toBranchId_);\n fromBranchId_ = (totalBranch_ < fromBranchId_ ? totalBranch_ : fromBranchId_);\n\n require(fromBranchId_ >= toBranchId_, \"fromBranchId_ must be greater than or equal to toBranchId_\");\n\n branchesDebt_ = new BranchDebt[](fromBranchId_ - toBranchId_ + 1);\n\n uint index_;\n\n for (uint i = fromBranchId_; i >= toBranchId_; i--) {\n branchesDebt_[index_++] = _getBranchDebt(vault_, vaultVariables_, i);\n }\n }\n\n function getMultipleVaultsBranchesDebt(\n address[] memory vaults_,\n uint[] memory fromBranchIds_,\n uint[] memory toBranchIds_\n ) external view returns (BranchesDebt[] memory branchesDebt_) {\n uint length_ = vaults_.length;\n\n branchesDebt_ = new BranchesDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n branchesDebt_[i].branchDebt = getBranchesDebt(vaults_[i], fromBranchIds_[i], toBranchIds_[i]);\n }\n }\n\n function getAllVaultsBranchesDebt() external view returns (BranchesDebt[] memory branchesDebt_) {\n address[] memory vaults_ = VAULT_RESOLVER.getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n branchesDebt_ = new BranchesDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n branchesDebt_[i].branchDebt = getBranchesDebt(vaults_[i], type(uint).max, 0);\n }\n }\n\n function _populateTicksDebt(\n address vault_,\n int toTick_,\n int mapId_,\n uint tickHasDebt_,\n uint count_,\n uint vaultSupplyExchangePrice_,\n uint vaultBorrowExchangePrice_\n ) internal view returns (TickDebt[] memory ticksDebt_) {\n ticksDebt_ = new TickDebt[](count_);\n\n count_ = 0; // reuse var for loop index counter\n int nextTick_;\n uint tickExistingRawDebt_;\n uint ratio_;\n uint collateralRaw_;\n\n while (true) {\n while (tickHasDebt_ > 0) {\n {\n uint msb_ = BigMathMinified.mostSignificantBit(tickHasDebt_);\n // removing next tick from tickHasDebt\n tickHasDebt_ = (tickHasDebt_ << (257 - msb_)) >> (257 - msb_);\n nextTick_ = mapId_ * 256 + int(msb_ - 1);\n }\n if (nextTick_ < toTick_) {\n return ticksDebt_;\n }\n tickExistingRawDebt_ = (VAULT_RESOLVER.getTickDataRaw(vault_, nextTick_) >> 25) & X64;\n tickExistingRawDebt_ = (tickExistingRawDebt_ >> 8) << (tickExistingRawDebt_ & X8);\n ratio_ = TickMath.getRatioAtTick(nextTick_);\n collateralRaw_ = (tickExistingRawDebt_ * (1 << 96)) / ratio_;\n ticksDebt_[count_++] = TickDebt({\n debtRaw: tickExistingRawDebt_,\n collateralRaw: collateralRaw_,\n debtNormal: (tickExistingRawDebt_ * vaultBorrowExchangePrice_) / 1e12,\n collateralNormal: (collateralRaw_ * vaultSupplyExchangePrice_) / 1e12,\n ratio: ratio_,\n tick: nextTick_\n });\n }\n\n if (--mapId_ == -129) {\n break;\n }\n\n tickHasDebt_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, mapId_);\n }\n }\n\n function _tickHelper(uint tickRaw_) internal pure returns (int tick) {\n require(tickRaw_ < X20, \"invalid-number\");\n if (tickRaw_ > 0) {\n tick = tickRaw_ & 1 == 1 ? int((tickRaw_ >> 1) & X19) : -int((tickRaw_ >> 1) & X19);\n } else {\n tick = type(int).min;\n }\n }\n\n function _countTicksWithDebt(\n address vault_,\n int toTick_,\n int mapId_,\n uint tickHasDebt_\n ) internal view returns (uint count_) {\n uint msb_;\n int nextTick_;\n while (true) {\n while (tickHasDebt_ > 0) {\n msb_ = BigMathMinified.mostSignificantBit(tickHasDebt_);\n // removing next tick from tickHasDebt\n tickHasDebt_ = (tickHasDebt_ << (257 - msb_)) >> (257 - msb_);\n nextTick_ = mapId_ * 256 + int(msb_ - 1);\n if (nextTick_ < toTick_) {\n return count_;\n }\n count_++;\n }\n\n if (--mapId_ == -129) {\n break;\n }\n tickHasDebt_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, mapId_);\n }\n return count_;\n }\n\n function _getBranchDebt(\n address vault_,\n uint vaultVariables_,\n uint branchId_\n ) internal view returns (BranchDebt memory) {\n uint currentBranchData_ = VAULT_RESOLVER.getBranchDataRaw(vault_, branchId_);\n\n int minimaTick_ = _tickHelper((currentBranchData_ >> 2) & X20);\n uint status_ = currentBranchData_ & 3;\n\n if (status_ == 0) {\n // not liquidated status == 0\n // only current branch can be non-liquidated branch\n return _getActiveBranchDebt(vaultVariables_, currentBranchData_, branchId_, status_);\n } else if (status_ == 1) {\n // liquidated status == 1\n return _getLiquidatedBranchDebt(vault_, currentBranchData_, branchId_, status_, minimaTick_);\n } else {\n // merged status == 2\n // absorbed status == 3\n return _getClosedOrMergedBranchDebt(currentBranchData_, branchId_, status_);\n }\n }\n\n function _getActiveBranchDebt(\n uint vaultVariables_,\n uint currentBranchData_,\n uint branchId_,\n uint status_\n ) internal pure returns (BranchDebt memory branchDebt_) {\n int topTick_ = _tickHelper((vaultVariables_ >> 2) & X20);\n\n uint ratio_ = topTick_ > type(int).min ? TickMath.getRatioAtTick(topTick_) : 0;\n\n branchDebt_ = BranchDebt({\n debtRaw: 0,\n collateralRaw: 0,\n debtNormal: 0,\n collateralNormal: 0,\n branchId: branchId_,\n status: status_, // active status\n tick: topTick_, // as branch is not liquidated, just returning topTick for now, as whenever liquidation starts it'll start from topTick\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: _tickHelper((currentBranchData_ >> 196) & X20) // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getClosedOrMergedBranchDebt(\n uint currentBranchData_,\n uint branchId_,\n uint status_\n ) internal pure returns (BranchDebt memory branchDebt_) {\n int baseBranchTick_ = _tickHelper((currentBranchData_ >> 196) & X20);\n uint ratio_ = baseBranchTick_ > type(int).min ? TickMath.getRatioAtTick(baseBranchTick_) : 0;\n\n branchDebt_ = BranchDebt({\n debtRaw: 0,\n collateralRaw: 0,\n debtNormal: 0,\n collateralNormal: 0,\n branchId: branchId_,\n status: status_,\n tick: baseBranchTick_, // as branch is merged/closed, so adding baseBranchTick_ as this is where it went out of existance\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: baseBranchTick_ // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getLiquidatedBranchDebt(\n address vault_,\n uint currentBranchData_,\n uint branchId_,\n uint status_,\n int minimaTick_\n ) internal view returns (BranchDebt memory branchDebt_) {\n uint debtLiquidity_ = BigMathMinified.fromBigNumber((currentBranchData_ >> 52) & X64, 8, X8);\n (uint collateralRaw_, uint ratio_) = _getCollateralRaw(currentBranchData_, debtLiquidity_, minimaTick_);\n\n (, , uint256 vaultSupplyExchangePrice_, uint256 vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\n branchDebt_ = BranchDebt({\n debtRaw: debtLiquidity_,\n collateralRaw: collateralRaw_,\n debtNormal: (debtLiquidity_ * vaultBorrowExchangePrice_) / 1e12,\n collateralNormal: (collateralRaw_ * vaultSupplyExchangePrice_) / 1e12,\n branchId: branchId_,\n status: status_,\n tick: minimaTick_, // as branch is merged/closed, so adding baseBranchTick_ as this is where it went out of existance\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: _tickHelper((currentBranchData_ >> 196) & X20) // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getCollateralRaw(\n uint currentBranchData_,\n uint debtLiquidity_,\n int minimaTick_\n ) internal pure returns (uint collateralRaw_, uint ratio_) {\n ratio_ = TickMath.getRatioAtTick(int24(minimaTick_));\n uint ratioOneLess_ = (ratio_ * 10000) / 10015;\n uint length_ = ratio_ - ratioOneLess_;\n uint partials_ = (currentBranchData_ >> 22) & X30;\n uint currentRatio_ = ratioOneLess_ + ((length_ * partials_) / X30);\n collateralRaw_ = (debtLiquidity_ * TickMath.ZERO_TICK_SCALED_RATIO) / currentRatio_;\n }\n}\n"
},
"contracts/periphery/resolvers/vaultTicksBranches/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Structs {\n struct TickDebt {\n uint256 debtRaw;\n uint256 collateralRaw;\n uint256 debtNormal; // debtRaw * exchange price\n uint256 collateralNormal; // collateralRaw * exchange price\n uint256 ratio;\n int256 tick;\n }\n\n struct VaultsTickDebt {\n TickDebt[] tickDebt;\n int toTick;\n }\n\n struct BranchDebt {\n uint256 debtRaw;\n uint256 collateralRaw;\n uint256 debtNormal; // debtRaw * exchange price\n uint256 collateralNormal; // collateralRaw * exchange price\n uint256 branchId;\n uint256 status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed\n int256 tick;\n uint256 partials;\n uint256 ratio;\n uint debtFactor; // debt factor or connection factor\n uint baseBranchId;\n int baseBranchTick;\n }\n\n struct BranchesDebt {\n BranchDebt[] branchDebt;\n }\n}\n"
},
"contracts/periphery/resolvers/vaultTicksBranches/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\n\ncontract Variables {\n IFluidVaultResolver public immutable VAULT_RESOLVER;\n\n uint internal constant X8 = 0xff;\n uint internal constant X19 = 0x7ffff;\n uint internal constant X20 = 0xfffff;\n uint internal constant X30 = 0x3fffffff;\n uint internal constant X50 = 0x3ffffffffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n\n constructor(IFluidVaultResolver vaultResolver_) {\n VAULT_RESOLVER = vaultResolver_;\n }\n}\n"
},
"contracts/protocols/flashloan/error.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Error {\n error FluidFlashLenderError(uint256 errorId_);\n}\n"
},
"contracts/protocols/flashloan/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | FlashLender | \n |__________________________________*/\n\n /// @notice Thrown when a function encounters or is provided with an address set to the zero address.\n uint256 internal constant FlashLender__ZeroAddress = 80001;\n\n /// @notice Thrown when the requested flash loan amount exceeds the allowed maximum.\n uint256 internal constant FlashLender__MaxFlashLoanAmountExceeded = 80002;\n\n /// @notice Thrown when a function returns an unexpected value.\n uint256 internal constant FlashLender__InvalidReturnValue = 80003;\n\n /// @notice Thrown when an unauthorized action is attempted.\n uint256 internal constant FlashLender__Unauthorized = 80004;\n\n /// @notice Thrown when an operation involves a token that isn't supported.\n uint256 internal constant FlashLender__TokenNotSupported = 80005;\n\n /// @notice Thrown when a token is already being borrowed by flashloan protocol.\n uint256 internal constant FlashLender__DuplicateBorrow = 80006;\n}\n"
},
"contracts/protocols/flashloan/helpers.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { LiquiditySlotsLink } from \"../../libraries/liquiditySlotsLink.sol\";\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\n\nimport { ErrorTypes } from \"./errorTypes.sol\";\nimport { Error } from \"./error.sol\";\nimport { Variables } from \"./variables.sol\";\n\n/// @dev Flashloan protocol helper methods\nabstract contract Helpers is Variables, Error {\n constructor(IFluidLiquidity liquidity_) Variables(liquidity_) {}\n\n /// @notice Reads user borrow data of currency to be lent.\n /// @param token_ The loan currency.\n /// @return user borrow data for `token`.\n function _readUserBorrowData(address token_) internal view returns (uint256) {\n bytes32 slot_ = LiquiditySlotsLink.calculateDoubleMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT,\n address(this),\n token_\n );\n return LIQUIDITY.readFromStorage(slot_);\n }\n\n /// @notice Checks if the given address is valid (not equal to address(0)).\n /// @param value_ The address to check..\n function _checkValidAddress(address value_) internal pure {\n if (value_ == address(0)) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__ZeroAddress);\n }\n }\n\n /// @notice Ensures that the provided address is valid (not equal to address(0)).\n /// @param value_ The address to check.\n modifier validAddress(address value_) {\n _checkValidAddress(value_);\n _;\n }\n}\n"
},
"contracts/protocols/flashloan/interfaces/IERC3156FlashBorrower.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IERC3156FlashBorrower {\n function onFlashLoan(\n address initiator,\n address token,\n uint256 amount,\n uint256 fee,\n bytes calldata data\n ) external returns (bytes32);\n}\n"
},
"contracts/protocols/flashloan/interfaces/IERC3156FlashLender.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport \"./IERC3156FlashBorrower.sol\";\n\ninterface IERC3156FlashLender {\n /// @dev The amount of currency available to be lent.\n /// @param token The loan currency.\n /// @return The amount of `token` that can be borrowed.\n function maxFlashLoan(address token) external view returns (uint256);\n\n /// @dev The fee to be charged for a given loan.\n /// @param token The loan currency.\n /// @param amount The amount of tokens lent.\n /// @return The amount of `token` to be charged for the loan, on top of the returned principal.\n function flashFee(address token, uint256 amount) external view returns (uint256);\n\n /// @dev Initiate a flash loan.\n /// @param receiver The receiver of the tokens in the loan, and the receiver of the callback.\n /// @param token The loan currency.\n /// @param amount The amount of tokens lent.\n /// @param data Arbitrary data structure, intended to contain user-defined parameters.\n function flashLoan(\n IERC3156FlashBorrower receiver,\n address token,\n uint256 amount,\n bytes calldata data\n ) external returns (bool);\n}\n"
},
"contracts/protocols/flashloan/interfaces/iFlashBorrower.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport \"./IERC3156FlashBorrower.sol\";\nimport { Structs } from \"../structs.sol\";\n\ninterface IFlashBorrower is IERC3156FlashBorrower {\n function onFlashLoanMultiple(\n address initiator,\n Structs.AddressUint256[] calldata tokensWithValues,\n uint256 fee,\n bytes calldata data\n ) external returns (bytes32);\n}\n"
},
"contracts/protocols/flashloan/interfaces/iFlashLender.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IFlashBorrower } from \"./iFlashBorrower.sol\";\nimport { IERC3156FlashLender } from \"./IERC3156FlashLender.sol\";\nimport { IERC3156FlashBorrower } from \"./IERC3156FlashBorrower.sol\";\nimport { Structs } from \"../structs.sol\";\n\ninterface IFluidFlashLender is IERC3156FlashLender {\n /// @notice Initiate a flash loan with multiple tokens.\n /// @param receiver_ The receiver of the tokens in the loan, and the receiver of the callback.\n /// @param tokensWithAmounts_ An array of token addresses and loan amounts.\n /// @param data_ Arbitrary data structure, intended to contain user-defined parameters.\n /// @return 'true' if the flash loan are successful\n function flashLoanMultiple(\n IFlashBorrower receiver_,\n Structs.AddressUint256[] calldata tokensWithAmounts_,\n bytes calldata data_\n ) external returns (bool);\n}\n"
},
"contracts/protocols/flashloan/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { Helpers } from \"./helpers.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { ErrorTypes } from \"./errorTypes.sol\";\nimport { IFluidFlashLender } from \"./interfaces/iFlashLender.sol\";\nimport { IERC3156FlashBorrower } from \"./interfaces/IERC3156FlashBorrower.sol\";\nimport { IFlashBorrower } from \"./interfaces/iFlashBorrower.sol\";\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\nimport { IProtocol } from \"../../liquidity/userModule/main.sol\";\n\nimport { LiquidityCalcs } from \"../../libraries/liquidityCalcs.sol\";\nimport { LiquiditySlotsLink } from \"../../libraries/liquiditySlotsLink.sol\";\n\n/// @notice contract that provides Flashloans via Fluid. ERC-3156 compatible.\n/// In addition also implements a `flashLoanMultiple()` method which can be used to flash loan multiple tokens at once.\n/// @dev Fee is a constant 0. This contract is not upgradeable.\n//\n// @dev Fee is not really implemented, just the parts that are needed to ensure compatibility with ERC-3156.\n// @dev user borrow amount for this contract at Liquidity will slowly grow but that is not an issue as the amount\n// being repaid is still the exact original amount always.\ncontract FluidFlashLender is Structs, IFluidFlashLender, IProtocol, Helpers {\n using SafeERC20 for IERC20;\n\n /// @notice emitted whenever funds for a certain `token` are rescued to Liquidity\n event LogRescueFunds(address indexed token);\n\n /// @notice emitted when a flashloan has been taken and repaid\n event LogFlashLoan(address indexed token, uint256 indexed amount, address indexed receiver);\n\n constructor(IFluidLiquidity liquidity_) Helpers(liquidity_) {}\n\n /// @notice The amount of currency available to be lent.\n /// @param token_ The loan currency.\n /// @return The amount of `token` that can be borrowed.\n function maxFlashLoan(address token_) public view returns (uint256) {\n // maximum flashloan is either:\n // a) the borrow limit of Flashloan protocol at Liquidity or\n // b) the total available amount of token at Liquidity (if lower than borrow limit)\n\n // get current exchange rates\n (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = LiquidityCalcs.calcExchangePrices(\n LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n token_\n )\n )\n );\n\n // a) get the borrow limit\n uint256 userBorrowData_ = _readUserBorrowData(token_);\n uint256 userBorrow_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & LiquidityCalcs.X64;\n // get borrow limit\n uint256 borrowLimit_ = LiquidityCalcs.calcBorrowLimitBeforeOperate(userBorrowData_, userBorrow_);\n // revert if Flashloan protocol has already borrowed more than 0.0001% of borrow limit for the `token_`. This\n // catches any duplicate token borrows. We can not just check for user borrow == 0 because of rounding.\n if (userBorrow_ > (borrowLimit_ / 100_000)) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__DuplicateBorrow);\n }\n // subtract any already borrowed amount\n borrowLimit_ -= userBorrow_;\n\n if (userBorrowData_ & 1 == 1) {\n // convert raw borrow limit amount to normal for withInterest mode\n borrowLimit_ = (borrowLimit_ * borrowExchangePrice_) / LiquidityCalcs.EXCHANGE_PRICES_PRECISION;\n }\n\n // b) get the total available amount at Liquidity (total supply - total borrow)\n uint256 totalAmounts_ = LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT,\n token_\n )\n );\n // totalSupply = supplyRawInterest normalized from raw + supplyInterestFree\n uint256 totalSupply_ = LiquidityCalcs.getTotalSupply(totalAmounts_, supplyExchangePrice_);\n // get total borrow for token interest free + with interest converted from raw\n uint256 totalBorrow_ = LiquidityCalcs.getTotalBorrow(totalAmounts_, borrowExchangePrice_);\n\n uint256 availableAmount_;\n unchecked {\n // todo: this amount would also have to include max utilization limit.\n // potential other updates might be needed in flashloan protocol before release as Liquidity layer\n // had some changes etc.\n availableAmount_ = totalBorrow_ > totalSupply_ ? 0 : totalSupply_ - totalBorrow_;\n }\n\n return borrowLimit_ < availableAmount_ ? borrowLimit_ : availableAmount_;\n }\n\n /// @notice The fee to be charged for a given loan.\n /// @param token_ loan currency.\n /// @param amount_ The amount of tokens lent.\n /// @return The amount of `token` to be charged for the loan, on top of the returned principal.\n function flashFee(address token_, uint256 amount_) external view returns (uint256) {\n if (_readUserBorrowData(token_) == 0) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__TokenNotSupported);\n }\n return _FLASH_FEE;\n }\n\n /// @notice Initiate a flash loan.\n /// @dev receiver_ must approve `amount_` of `token_` for payback. For native token, it must be send as msg.value.\n /// @param receiver_ The receiver of the tokens in the loan, and the receiver of the callback.\n /// @param token_ The loan currency.\n /// @param amount_ The amount of tokens lent.\n /// @param data_ Arbitrary data structure, intended to contain user-defined parameters.\n function flashLoan(\n IERC3156FlashBorrower receiver_,\n address token_,\n uint256 amount_,\n bytes calldata data_\n ) external validAddress(address(receiver_)) validAddress(token_) returns (bool) {\n if (amount_ > maxFlashLoan(token_)) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__MaxFlashLoanAmountExceeded);\n }\n\n LIQUIDITY.operate(token_, 0, SafeCast.toInt256(amount_), address(0), address(receiver_), new bytes(0));\n\n if (\n receiver_.onFlashLoan(msg.sender, token_, amount_, _FLASH_FEE, data_) != _RETURN_VALUE_FOR_FLASHLOAN_SINGLE\n ) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__InvalidReturnValue);\n }\n\n LIQUIDITY.operate{ value: token_ == _NATIVE_TOKEN_ADDRESS ? amount_ : 0 }(\n token_,\n 0,\n -int256(amount_),\n address(0),\n address(0),\n abi.encode(address(receiver_))\n );\n\n emit LogFlashLoan(token_, amount_, address(receiver_));\n\n return true;\n }\n\n /// @notice Initiate a flash loan with multiple tokens.\n /// @dev receiver_ must approve `amount_` of each token for payback. For native token, it must be send as msg.value.\n /// @param receiver_ The receiver of the tokens in the loan, and the receiver of the callback.\n /// @param tokensWithAmounts_ An array of token addresses and loan amounts.\n /// @param data_ Arbitrary data structure, intended to contain user-defined parameters.\n /// @return 'true' if the flash loans are successful\n function flashLoanMultiple(\n IFlashBorrower receiver_,\n AddressUint256[] calldata tokensWithAmounts_,\n bytes calldata data_\n ) external validAddress(address(receiver_)) returns (bool) {\n uint256 length_ = tokensWithAmounts_.length;\n\n // execute all borrows at Liquidity\n for (uint256 i; i < length_; ) {\n _checkValidAddress(tokensWithAmounts_[i].addr);\n if (tokensWithAmounts_[i].value > maxFlashLoan(tokensWithAmounts_[i].addr)) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__MaxFlashLoanAmountExceeded);\n }\n\n LIQUIDITY.operate(\n tokensWithAmounts_[i].addr,\n 0,\n SafeCast.toInt256(tokensWithAmounts_[i].value),\n address(0),\n address(receiver_),\n new bytes(0)\n );\n\n unchecked {\n i++;\n }\n }\n\n if (\n //onFlashLoanMultiple or onFlashLoan callback and then we could put tokens with amounts if data callback\n receiver_.onFlashLoanMultiple(msg.sender, tokensWithAmounts_, _FLASH_FEE, data_) !=\n _RETURN_VALUE_FOR_FLASHLOAN_MULTIPLE\n ) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__InvalidReturnValue);\n }\n\n // execute all paybacks at Liquidity\n for (uint256 i; i < length_; ) {\n {\n address receiverAddress_ = address(receiver_); // required to avoid stack too deep error\n\n LIQUIDITY.operate{\n value: tokensWithAmounts_[i].addr == _NATIVE_TOKEN_ADDRESS ? tokensWithAmounts_[i].value : 0\n }(\n tokensWithAmounts_[i].addr,\n 0,\n -int256(tokensWithAmounts_[i].value),\n address(0),\n address(0),\n abi.encode(receiverAddress_)\n );\n\n emit LogFlashLoan(tokensWithAmounts_[i].addr, tokensWithAmounts_[i].value, receiverAddress_);\n }\n\n unchecked {\n i++;\n }\n }\n\n return true;\n }\n\n /// @notice flashLender liquidity callback\n /// @param token_ The token being transferred\n /// @param amount_ The amount being transferred\n function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external {\n if (msg.sender != address(LIQUIDITY)) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__Unauthorized);\n }\n\n address receiver_ = abi.decode(data_, (address));\n IERC20(token_).safeTransferFrom(receiver_, address(LIQUIDITY), amount_);\n }\n\n /// @dev @Fallback function to receive Ether\n receive() external payable {}\n\n /// @notice sends any potentially stuck funds to Liquidity contract. Only callable by Liquidity auths.\n //\n // @dev this contract never holds any funds:\n // -> borrowed funds are directly sent from Liquidity to the receiver.\n // -> at payback, only approval is given by receiver to this contract but funds are directly transferred from\n // receiver to Liquidity. For native token, msg.value is sent forward to Liquidity operate() call.\n // Thus we can simply create a method to rescue any potentially stuck funds by sending them to Liquidity,\n // where that excess amount is recognized as revenue and could be withdrawn by Governance.\n function rescueFunds(address token_) external {\n if (\n // msg.sender must be an auth or Governance at Liquidity\n (LIQUIDITY.readFromStorage(\n LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_AUTHS_MAPPING_SLOT,\n msg.sender\n )\n ) &\n 1 !=\n 1) && address(uint160(LIQUIDITY.readFromStorage(_GOVERNANCE_SLOT))) != msg.sender\n ) {\n revert FluidFlashLenderError(ErrorTypes.FlashLender__Unauthorized);\n }\n\n if (token_ == _NATIVE_TOKEN_ADDRESS) {\n Address.sendValue(payable(address(LIQUIDITY)), address(this).balance);\n } else {\n IERC20(token_).safeTransfer(address(LIQUIDITY), IERC20(token_).balanceOf(address(this)));\n }\n\n emit LogRescueFunds(token_);\n }\n\n /// @notice repays `repayAmount_` for `token_` at Liquidity.\n /// Can be used to balance out any leftover rounding differences at Liquidity if ever needed.\n function repayAtLiquidity(address token_, uint256 repayAmount_) external payable {\n LIQUIDITY.operate{ value: msg.value }(\n token_,\n 0,\n -int256(repayAmount_),\n address(0),\n address(0),\n abi.encode(msg.sender)\n );\n }\n}\n"
},
"contracts/protocols/flashloan/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Structs {\n struct AddressUint256 {\n address addr;\n uint256 value;\n }\n}\n"
},
"contracts/protocols/flashloan/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\n\nabstract contract Variables {\n /// @dev address that is mapped to the chain native token\n address internal constant _NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n bytes32 internal constant _RETURN_VALUE_FOR_FLASHLOAN_SINGLE = keccak256(\"ERC3156FlashBorrower.onFlashLoan\");\n bytes32 internal constant _RETURN_VALUE_FOR_FLASHLOAN_MULTIPLE = keccak256(\"FlashBorrower.onFlashLoanMultiple\");\n\n /// @dev Storage slot with the admin of the contract at Liquidity. Logic from \"proxy.sol\".\n /// This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1.\n bytes32 internal constant _GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /// @dev fee for flashloan set globally for all tokens\n //\n // @dev can't just change this to a value != 0 as that case is not fully implemented. Ensure necessary changes are\n // made if _FLASH_FEE must be set to value != 0.\n uint256 internal constant _FLASH_FEE = 0;\n\n /// @notice address of the Fluid Liquidity contract\n IFluidLiquidity public immutable LIQUIDITY;\n\n constructor(IFluidLiquidity liquidity_) {\n LIQUIDITY = liquidity_;\n }\n}\n"
},
"contracts/protocols/vault/interfaces/iVaultFactory.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC721Enumerable } from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol\";\n\ninterface IFluidVaultFactory is IERC721Enumerable {\n /// @notice Minting an NFT Vault for the user\n function mint(uint256 vaultId_, address user_) external returns (uint256 tokenId_);\n\n /// @notice returns owner of Vault which is also an NFT\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /// @notice Global auth is auth for all vaults\n function isGlobalAuth(address auth_) external view returns (bool);\n\n /// @notice Vault auth is auth for a specific vault\n function isVaultAuth(address vault_, address auth_) external view returns (bool);\n\n /// @notice Total vaults deployed.\n function totalVaults() external view returns (uint256);\n\n /// @notice Compute vaultAddress\n function getVaultAddress(uint256 vaultId) external view returns (address);\n\n /// @notice read uint256 `result_` for a storage `slot_` key\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n"
},
"contracts/protocols/vault/interfaces/iVaultT1.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidVaultT1 {\n /// @notice returns the vault id\n function VAULT_ID() external view returns (uint256);\n\n /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n\n struct ConstantViews {\n address liquidity;\n address factory;\n address adminImplementation;\n address secondaryImplementation;\n address supplyToken;\n address borrowToken;\n uint8 supplyDecimals;\n uint8 borrowDecimals;\n uint vaultId;\n bytes32 liquiditySupplyExchangePriceSlot;\n bytes32 liquidityBorrowExchangePriceSlot;\n bytes32 liquidityUserSupplySlot;\n bytes32 liquidityUserBorrowSlot;\n }\n\n /// @notice returns all Vault constants\n function constantsView() external view returns (ConstantViews memory constantsView_);\n\n /// @notice fetches the latest user position after a liquidation\n function fetchLatestPosition(\n int256 positionTick_,\n uint256 positionTickId_,\n uint256 positionRawDebt_,\n uint256 tickData_\n )\n external\n view\n returns (\n int256, // tick\n uint256, // raw debt\n uint256, // raw collateral\n uint256, // branchID_\n uint256 // branchData_\n );\n\n /// @notice calculates the updated vault exchange prices\n function updateExchangePrices(\n uint256 vaultVariables2_\n )\n external\n view\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n );\n\n /// @notice calculates the updated vault exchange prices and writes them to storage\n function updateExchangePricesOnStorage()\n external\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n );\n\n /// @notice returns the liquidity contract address\n function LIQUIDITY() external view returns (address);\n\n function operate(\n uint256 nftId_, // if 0 then new position\n int256 newCol_, // if negative then withdraw\n int256 newDebt_, // if negative then payback\n address to_ // address at which the borrow & withdraw amount should go to. If address(0) then it'll go to msg.sender\n )\n external\n payable\n returns (\n uint256, // nftId_\n int256, // final supply amount. if - then withdraw\n int256 // final borrow amount. if - then payback\n );\n \n function liquidate(\n uint256 debtAmt_,\n uint256 colPerUnitDebt_, // min collateral needed per unit of debt in 1e18\n address to_,\n bool absorb_\n ) external payable returns (uint actualDebtAmt_, uint actualColAmt_);\n\n function absorb() external;\n\n function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);\n\n error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);\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": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}