fluid-contracts-public/deployments/arbitrum/solcInputs/8229d0a2b99e4833044b24bf8dcbcc02.json
2024-07-11 13:05:09 +00:00

180 lines
288 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/interfaces/IERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-users” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-users” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vaults underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vaults underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256 assets);\n}\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/extensions/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/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"
},
"contracts/config/error.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n error FluidConfigError(uint256 errorId_);\n}\n"
},
"contracts/config/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | ExpandPercentConfigHandler | \n |__________________________________*/\n\n /// @notice thrown when an input address is zero\n uint256 internal constant ExpandPercentConfigHandler__AddressZero = 100001;\n\n /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n uint256 internal constant ExpandPercentConfigHandler__Unauthorized = 100002;\n\n /// @notice thrown when invalid params are passed into a method\n uint256 internal constant ExpandPercentConfigHandler__InvalidParams = 100003;\n\n /// @notice thrown when no update is currently needed\n uint256 internal constant ExpandPercentConfigHandler__NoUpdate = 100004;\n\n /// @notice thrown when slot is not used, e.g. when borrow token is 0 there is no borrow data\n uint256 internal constant ExpandPercentConfigHandler__SlotDoesNotExist = 100005;\n\n /***********************************|\n | EthenaRateConfigHandler | \n |__________________________________*/\n\n /// @notice thrown when an input address is zero\n uint256 internal constant EthenaRateConfigHandler__AddressZero = 100011;\n\n /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n uint256 internal constant EthenaRateConfigHandler__Unauthorized = 100012;\n\n /// @notice thrown when invalid params are passed into a method\n uint256 internal constant EthenaRateConfigHandler__InvalidParams = 100013;\n\n /// @notice thrown when no update is currently needed\n uint256 internal constant EthenaRateConfigHandler__NoUpdate = 100014;\n\n /***********************************|\n | MaxBorrowConfigHandler | \n |__________________________________*/\n\n /// @notice thrown when an input address is zero\n uint256 internal constant MaxBorrowConfigHandler__AddressZero = 100021;\n\n /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n uint256 internal constant MaxBorrowConfigHandler__Unauthorized = 100022;\n\n /// @notice thrown when invalid params are passed into a method\n uint256 internal constant MaxBorrowConfigHandler__InvalidParams = 100023;\n\n /// @notice thrown when no update is currently needed\n uint256 internal constant MaxBorrowConfigHandler__NoUpdate = 100024;\n\n /***********************************|\n | BufferRateConfigHandler | \n |__________________________________*/\n\n /// @notice thrown when an input address is zero\n uint256 internal constant BufferRateConfigHandler__AddressZero = 100031;\n\n /// @notice thrown when an unauthorized `msg.sender` calls a protected method\n uint256 internal constant BufferRateConfigHandler__Unauthorized = 100032;\n\n /// @notice thrown when invalid params are passed into a method\n uint256 internal constant BufferRateConfigHandler__InvalidParams = 100033;\n\n /// @notice thrown when no update is currently needed\n uint256 internal constant BufferRateConfigHandler__NoUpdate = 100034;\n\n /// @notice thrown when rate data version is not supported\n uint256 internal constant BufferRateConfigHandler__RateVersionUnsupported = 100035;\n}\n"
},
"contracts/config/ethenaRateHandler/events.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Events {\n /// @notice emitted when borrow magnifier is updated at vault\n event LogUpdateBorrowRateMagnifier(uint256 oldMagnifier, uint256 newMagnifier);\n}\n"
},
"contracts/config/ethenaRateHandler/interfaces/iStakedUSDe.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC4626 } from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\n\ninterface IStakedUSDe is IERC4626 {\n /// @notice The amount of the last asset distribution from the controller contract into this\n /// contract + any unvested remainder at that time\n function vestingAmount() external view returns (uint256);\n\n /// @notice The timestamp of the last asset distribution from the controller contract into this contract\n function lastDistributionTimestamp() external view returns (uint256);\n\n /// @notice Returns the amount of USDe tokens that are vested in the contract.\n function totalAssets() external view returns (uint256);\n}\n"
},
"contracts/config/ethenaRateHandler/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidReserveContract } from \"../../reserve/interfaces/iReserveContract.sol\";\nimport { IFluidVaultT1 } from \"../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { LiquiditySlotsLink } from \"../../libraries/liquiditySlotsLink.sol\";\nimport { FluidVaultT1Admin } from \"../../protocols/vault/vaultT1/adminModule/main.sol\";\nimport { IStakedUSDe } from \"./interfaces/iStakedUSDe.sol\";\nimport { Variables } from \"./variables.sol\";\nimport { Events } from \"./events.sol\";\nimport { Error } from \"../error.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\n/// @notice Sets borrow rate for sUSDe/debtToken vaults based on sUSDe yield rate, by adjusting the borrowRateMagnifier\ncontract FluidEthenaRateConfigHandler is Variables, Error, Events {\n /// @dev Validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidConfigError(ErrorTypes.EthenaRateConfigHandler__AddressZero);\n }\n _;\n }\n\n /// @dev Validates that an address is a rebalancer (taken from reserve contract)\n modifier onlyRebalancer() {\n if (!RESERVE_CONTRACT.isRebalancer(msg.sender)) {\n revert FluidConfigError(ErrorTypes.EthenaRateConfigHandler__Unauthorized);\n }\n _;\n }\n\n constructor(\n IFluidReserveContract reserveContract_,\n IFluidLiquidity liquidity_,\n IFluidVaultT1 vault_,\n IStakedUSDe stakedUSDe_,\n address borrowToken_,\n uint256 ratePercentMargin_,\n uint256 maxRewardsDelay_,\n uint256 utilizationPenaltyStart_,\n uint256 utilization100PenaltyPercent_\n )\n validAddress(address(reserveContract_))\n validAddress(address(liquidity_))\n validAddress(address(vault_))\n validAddress(address(stakedUSDe_))\n validAddress(borrowToken_)\n {\n if (\n ratePercentMargin_ == 0 ||\n ratePercentMargin_ >= 1e4 ||\n maxRewardsDelay_ == 0 ||\n utilizationPenaltyStart_ >= 1e4 ||\n utilization100PenaltyPercent_ == 0\n ) {\n revert FluidConfigError(ErrorTypes.EthenaRateConfigHandler__InvalidParams);\n }\n\n RESERVE_CONTRACT = reserveContract_;\n LIQUIDITY = liquidity_;\n SUSDE = stakedUSDe_;\n VAULT = vault_;\n BORROW_TOKEN = borrowToken_;\n\n _LIQUDITY_BORROW_TOKEN_EXCHANGE_PRICES_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n borrowToken_\n );\n\n RATE_PERCENT_MARGIN = ratePercentMargin_;\n MAX_REWARDS_DELAY = maxRewardsDelay_;\n\n UTILIZATION_PENALTY_START = utilizationPenaltyStart_;\n UTILIZATION100_PENALTY_PERCENT = utilization100PenaltyPercent_;\n }\n\n /// @notice Rebalances the borrow rate magnifier for `VAULT` based on borrow rate at Liquidity in relation to\n /// sUSDe yield rate (`getSUSDEYieldRate()`).\n /// Emits `LogUpdateBorrowRateMagnifier` in case of update. Reverts if no update is needed.\n /// Can only be called by an authorized rebalancer.\n function rebalance() external onlyRebalancer {\n uint256 targetMagnifier_ = calculateMagnifier();\n uint256 currentMagnifier_ = currentMagnifier();\n\n // execute update on vault if necessary\n if (targetMagnifier_ == currentMagnifier_) {\n revert FluidConfigError(ErrorTypes.EthenaRateConfigHandler__NoUpdate);\n }\n\n FluidVaultT1Admin(address(VAULT)).updateBorrowRateMagnifier(targetMagnifier_);\n\n emit LogUpdateBorrowRateMagnifier(currentMagnifier_, targetMagnifier_);\n }\n\n /// @notice Calculates the new borrow rate magnifier based on sUSDe yield rate and utilization\n /// @return magnifier_ the calculated magnifier value.\n function calculateMagnifier() public view returns (uint256 magnifier_) {\n uint256 sUSDeYieldRate_ = getSUSDeYieldRate();\n uint256 exchangePriceAndConfig_ = LIQUIDITY.readFromStorage(_LIQUDITY_BORROW_TOKEN_EXCHANGE_PRICES_SLOT);\n\n uint256 utilization_ = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14;\n\n // calculate target borrow rate. scaled by 1e18.\n // borrow rate is based on sUSDeYieldRate_ and a margin that goes to lenders\n // e.g. when RATE_PERCENT_MARGIN = 1000 (10%), then borrow rate will be 90% of the sUSDe yield rate\n // e.g. when sUSDe yield is 60%, borrow rate would be 54%\n uint256 targetBorrowRate_ = (sUSDeYieldRate_ * (1e4 - RATE_PERCENT_MARGIN)) / 1e4;\n\n if (utilization_ > UTILIZATION_PENALTY_START) {\n // above UTILIZATION_PENALTY_START (e.g. 90%), penalty should rise linearly according to UTILIZATION100_PENALTY_PERCENT\n // e.g. from 10% margin at 90% utilization to -3% penalty at 100% utilization\n // so from +RATE_PERCENT_MARGIN at UTILIZATION_PENALTY_START to -UTILIZATION100_PENALTY_PERCENT at 100%\n if (utilization_ < 1e4) {\n uint256 utilizationAbovePenaltyStart_ = utilization_ - UTILIZATION_PENALTY_START;\n uint256 penaltyUtilizationDiff_ = 1e4 - UTILIZATION_PENALTY_START;\n uint256 penaltyRateDiff_ = RATE_PERCENT_MARGIN + UTILIZATION100_PENALTY_PERCENT;\n\n // e.g. when current utilization = 96%, start penalty utilization = 90%, penalty at 100 = 3%, rate margin = 90%:\n // utilizationAbovePenaltyStart_ = 600 (6%)\n // penaltyUtilizationDiff_ = 1000 (10%)\n // penaltyRateDiff_ = 1000 + 300 = 1300 (13%)\n // marginAfterPenalty_ = 1300 * 600 / 1000 = 780 (7.8%)\n uint256 marginAfterPenalty_ = (penaltyRateDiff_ * utilizationAbovePenaltyStart_) /\n penaltyUtilizationDiff_;\n\n // e.g. when sUSDe yield is 60%, borrow rate would become 58.68% (from 60% * (90% + 7.8%) / 100% )\n targetBorrowRate_ = (sUSDeYieldRate_ * ((1e4 - RATE_PERCENT_MARGIN) + marginAfterPenalty_)) / 1e4;\n } else {\n // above 100% utilization, cap at -UTILIZATION100_PENALTY_PERCENT penalty\n targetBorrowRate_ = (sUSDeYieldRate_ * (1e4 + UTILIZATION100_PENALTY_PERCENT)) / 1e4;\n }\n }\n\n // get current neutral borrow rate at Liquidity (without any magnifier).\n // exchangePriceAndConfig slot at Liquidity, first 16 bits\n uint256 liquidityBorrowRate_ = exchangePriceAndConfig_ & X16;\n\n if (liquidityBorrowRate_ == 0) {\n return 1e4;\n }\n\n // calculate magnifier needed to reach target borrow rate.\n // liquidityBorrowRate_ * x = targetBorrowRate_. so x = targetBorrowRate_ / liquidityBorrowRate_.\n // must scale liquidityBorrowRate_ from 1e2 to 1e18 as targetBorrowRate_ is in 1e18. magnifier itself is scaled\n // by 1e4 (1x = 10000)\n magnifier_ = (1e4 * targetBorrowRate_) / (liquidityBorrowRate_ * 1e16);\n\n // make sure magnifier is within allowed limits\n if (magnifier_ < _MIN_MAGNIFIER) {\n return _MIN_MAGNIFIER;\n }\n if (magnifier_ > _MAX_MAGNIFIER) {\n return _MAX_MAGNIFIER;\n }\n }\n\n /// @notice returns the currently configured borrow magnifier at the `VAULT`.\n function currentMagnifier() public view returns (uint256) {\n // read borrow rate magnifier from Vault `vaultVariables2` located in storage slot 1, 16 bits from 16-31\n return (VAULT.readFromStorage(bytes32(uint256(1))) >> 16) & X16;\n }\n\n /// @notice calculates updated vesting yield rate based on `vestingAmount` and `totalAssets` of StakedUSDe contract\n /// @return rate_ sUSDe yearly yield rate scaled by 1e18 (1e18 = 1%, 1e20 = 100%)\n function getSUSDeYieldRate() public view returns (uint256 rate_) {\n if (block.timestamp > SUSDE.lastDistributionTimestamp() + _SUSDE_VESTING_PERIOD + MAX_REWARDS_DELAY) {\n // if rewards update on StakedUSDe contract is delayed by more than `MAX_REWARDS_DELAY`, we use rate as 0\n // as we can't know if e.g. funding would have gone negative and there are indeed no rewards.\n return 0;\n }\n\n // vestingAmount is yield per 8 hours (`SUSDE_VESTING_PERIOD`)\n rate_ = (SUSDE.vestingAmount() * 1e20) / SUSDE.totalAssets(); // 8 hours rate\n // turn into yearly yield\n rate_ = (rate_ * 365 * 24 hours) / _SUSDE_VESTING_PERIOD; // 365 days * 24 hours / 8 hours -> rate_ * 1095\n }\n}\n"
},
"contracts/config/ethenaRateHandler/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\nimport { IFluidReserveContract } from \"../../reserve/interfaces/iReserveContract.sol\";\nimport { IFluidVaultT1 } from \"../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { IStakedUSDe } from \"./interfaces/iStakedUSDe.sol\";\n\nabstract contract Constants {\n IFluidReserveContract public immutable RESERVE_CONTRACT;\n IFluidLiquidity public immutable LIQUIDITY;\n IFluidVaultT1 public immutable VAULT;\n IStakedUSDe public immutable SUSDE;\n address public immutable BORROW_TOKEN;\n\n /// @notice sUSDe vesting yield reward rate percent margin that goes to lenders\n /// e.g. RATE_PERCENT_MARGIN = 10% then borrow rate for debt token ends up as 90% of the sUSDe yield.\n /// (in 1e2: 100% = 10_000; 1% = 100)\n uint256 public immutable RATE_PERCENT_MARGIN;\n\n /// @notice max delay in seconds for rewards update after vesting period ended, after which we assume rate is 0.\n /// e.g. 15 min\n uint256 public immutable MAX_REWARDS_DELAY;\n\n /// @notice utilization penalty start point (in 1e2: 100% = 10_000; 1% = 100). above this, a penalty percent\n /// is applied, to incentivize deleveraging.\n uint256 public immutable UTILIZATION_PENALTY_START;\n /// @notice penalty percent target at 100%, on top of sUSDe yield rate if utilization is above UTILIZATION_PENALTY_START\n /// (in 1e2: 100% = 10_000; 1% = 100)\n uint256 public immutable UTILIZATION100_PENALTY_PERCENT;\n\n bytes32 internal immutable _LIQUDITY_BORROW_TOKEN_EXCHANGE_PRICES_SLOT;\n\n /// @dev vesting period defined as private constant on StakedUSDe contract\n uint256 internal constant _SUSDE_VESTING_PERIOD = 8 hours;\n\n uint256 internal constant X14 = 0x3fff;\n uint256 internal constant X16 = 0xffff;\n uint256 internal constant _MIN_MAGNIFIER = 1e4; // min magnifier is always at least 1x (10000)\n uint256 internal constant _MAX_MAGNIFIER = 65535; // max magnifier to fit in storage slot is 65535 (16 bits)\n}\n\nabstract contract Variables is Constants {}\n"
},
"contracts/infiniteProxy/error.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ncontract Error {\n error FluidInfiniteProxyError(uint256 errorId_);\n}\n"
},
"contracts/infiniteProxy/errorTypes.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | Infinite proxy | \n |__________________________________*/\n\n /// @notice thrown when an implementation does not exist\n uint256 internal constant InfiniteProxy__ImplementationNotExist = 50001;\n}\n"
},
"contracts/infiniteProxy/events.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Events {\n /// @notice emitted when a new admin is set\n event LogSetAdmin(address indexed oldAdmin, address indexed newAdmin);\n\n /// @notice emitted when a new dummy implementation is set\n event LogSetDummyImplementation(address indexed oldDummyImplementation, address indexed newDummyImplementation);\n\n /// @notice emitted when a new implementation is set with certain sigs\n event LogSetImplementation(address indexed implementation, bytes4[] sigs);\n\n /// @notice emitted when an implementation is removed\n event LogRemoveImplementation(address indexed implementation);\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/infiniteProxy/proxy.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Events } from \"./events.sol\";\nimport { ErrorTypes } from \"./errorTypes.sol\";\nimport { Error } from \"./error.sol\";\nimport { StorageRead } from \"../libraries/storageRead.sol\";\n\ncontract CoreInternals is StorageRead, Events, Error {\n struct SigsSlot {\n bytes4[] value;\n }\n\n /// @dev Storage slot with the admin of the contract.\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 _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /// @dev Storage slot with the address of the current dummy-implementation.\n /// This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n /// validated in the constructor.\n bytes32 internal constant _DUMMY_IMPLEMENTATION_SLOT =\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /// @dev use EIP1967 proxy slot (see _DUMMY_IMPLEMENTATION_SLOT) except for first 4 bytes,\n // which are set to 0. This is combined with a sig which will be set in those first 4 bytes\n bytes32 internal constant _SIG_SLOT_BASE = 0x000000003ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /// @dev Returns the storage slot which stores the sigs array set for the implementation.\n function _getSlotImplSigsSlot(address implementation_) internal pure returns (bytes32) {\n return keccak256(abi.encode(\"eip1967.proxy.implementation\", implementation_));\n }\n\n /// @dev Returns the storage slot which stores the implementation address for the function sig.\n function _getSlotSigsImplSlot(bytes4 sig_) internal pure returns (bytes32 result_) {\n assembly {\n // or operator sets sig_ in first 4 bytes with rest of bytes32 having default value of _SIG_SLOT_BASE\n result_ := or(_SIG_SLOT_BASE, sig_)\n }\n }\n\n /// @dev Returns an address `data_` located at `slot_`.\n function _getAddressSlot(bytes32 slot_) internal view returns (address data_) {\n assembly {\n data_ := sload(slot_)\n }\n }\n\n /// @dev Sets an address `data_` located at `slot_`.\n function _setAddressSlot(bytes32 slot_, address data_) internal {\n assembly {\n sstore(slot_, data_)\n }\n }\n\n /// @dev Returns an `SigsSlot` with member `value` located at `slot`.\n function _getSigsSlot(bytes32 slot_) internal pure returns (SigsSlot storage _r) {\n assembly {\n _r.slot := slot_\n }\n }\n\n /// @dev Sets new implementation and adds mapping from implementation to sigs and sig to implementation.\n function _setImplementationSigs(address implementation_, bytes4[] memory sigs_) internal {\n require(sigs_.length != 0, \"no-sigs\");\n bytes32 slot_ = _getSlotImplSigsSlot(implementation_);\n bytes4[] memory sigsCheck_ = _getSigsSlot(slot_).value;\n require(sigsCheck_.length == 0, \"implementation-already-exist\");\n\n for (uint256 i; i < sigs_.length; i++) {\n bytes32 sigSlot_ = _getSlotSigsImplSlot(sigs_[i]);\n require(_getAddressSlot(sigSlot_) == address(0), \"sig-already-exist\");\n _setAddressSlot(sigSlot_, implementation_);\n }\n\n _getSigsSlot(slot_).value = sigs_;\n emit LogSetImplementation(implementation_, sigs_);\n }\n\n /// @dev Removes implementation and the mappings corresponding to it.\n function _removeImplementationSigs(address implementation_) internal {\n bytes32 slot_ = _getSlotImplSigsSlot(implementation_);\n bytes4[] memory sigs_ = _getSigsSlot(slot_).value;\n require(sigs_.length != 0, \"implementation-not-exist\");\n\n for (uint256 i; i < sigs_.length; i++) {\n bytes32 sigSlot_ = _getSlotSigsImplSlot(sigs_[i]);\n _setAddressSlot(sigSlot_, address(0));\n }\n\n delete _getSigsSlot(slot_).value;\n emit LogRemoveImplementation(implementation_);\n }\n\n /// @dev Returns bytes4[] sigs from implementation address. If implemenatation is not registered then returns empty array.\n function _getImplementationSigs(address implementation_) internal view returns (bytes4[] memory) {\n bytes32 slot_ = _getSlotImplSigsSlot(implementation_);\n return _getSigsSlot(slot_).value;\n }\n\n /// @dev Returns implementation address from bytes4 sig. If sig is not registered then returns address(0).\n function _getSigImplementation(bytes4 sig_) internal view returns (address implementation_) {\n bytes32 slot_ = _getSlotSigsImplSlot(sig_);\n return _getAddressSlot(slot_);\n }\n\n /// @dev Returns the current admin.\n function _getAdmin() internal view returns (address) {\n return _getAddressSlot(_ADMIN_SLOT);\n }\n\n /// @dev Returns the current dummy-implementation.\n function _getDummyImplementation() internal view returns (address) {\n return _getAddressSlot(_DUMMY_IMPLEMENTATION_SLOT);\n }\n\n /// @dev Stores a new address in the EIP1967 admin slot.\n function _setAdmin(address newAdmin_) internal {\n address oldAdmin_ = _getAdmin();\n require(newAdmin_ != address(0), \"ERC1967: new admin is the zero address\");\n _setAddressSlot(_ADMIN_SLOT, newAdmin_);\n emit LogSetAdmin(oldAdmin_, newAdmin_);\n }\n\n /// @dev Stores a new address in the EIP1967 implementation slot.\n function _setDummyImplementation(address newDummyImplementation_) internal {\n address oldDummyImplementation_ = _getDummyImplementation();\n _setAddressSlot(_DUMMY_IMPLEMENTATION_SLOT, newDummyImplementation_);\n emit LogSetDummyImplementation(oldDummyImplementation_, newDummyImplementation_);\n }\n}\n\ncontract AdminInternals is CoreInternals {\n /// @dev Only admin guard\n modifier onlyAdmin() {\n require(msg.sender == _getAdmin(), \"only-admin\");\n _;\n }\n\n constructor(address admin_, address dummyImplementation_) {\n _setAdmin(admin_);\n _setDummyImplementation(dummyImplementation_);\n }\n\n /// @dev Sets new admin.\n function setAdmin(address newAdmin_) external onlyAdmin {\n _setAdmin(newAdmin_);\n }\n\n /// @dev Sets new dummy-implementation.\n function setDummyImplementation(address newDummyImplementation_) external onlyAdmin {\n _setDummyImplementation(newDummyImplementation_);\n }\n\n /// @dev Adds new implementation address.\n function addImplementation(address implementation_, bytes4[] calldata sigs_) external onlyAdmin {\n _setImplementationSigs(implementation_, sigs_);\n }\n\n /// @dev Removes an existing implementation address.\n function removeImplementation(address implementation_) external onlyAdmin {\n _removeImplementationSigs(implementation_);\n }\n}\n\n/// @title Proxy\n/// @notice This abstract contract provides a fallback function that delegates all calls to another contract using the EVM.\n/// It implements the Instadapp infinite-proxy: https://github.com/Instadapp/infinite-proxy\nabstract contract Proxy is AdminInternals {\n constructor(address admin_, address dummyImplementation_) AdminInternals(admin_, dummyImplementation_) {}\n\n /// @dev Returns admin's address.\n function getAdmin() external view returns (address) {\n return _getAdmin();\n }\n\n /// @dev Returns dummy-implementations's address.\n function getDummyImplementation() external view returns (address) {\n return _getDummyImplementation();\n }\n\n /// @dev Returns bytes4[] sigs from implementation address If not registered then returns empty array.\n function getImplementationSigs(address impl_) external view returns (bytes4[] memory) {\n return _getImplementationSigs(impl_);\n }\n\n /// @dev Returns implementation address from bytes4 sig. If sig is not registered then returns address(0).\n function getSigsImplementation(bytes4 sig_) external view returns (address) {\n return _getSigImplementation(sig_);\n }\n\n /// @dev Fallback function that delegates calls to the address returned by Implementations registry.\n fallback() external payable {\n address implementation_;\n assembly {\n // get slot for sig and directly SLOAD implementation address from storage at that slot\n implementation_ := sload(\n // same as in `_getSlotSigsImplSlot()` but we must also load msg.sig from calldata.\n // msg.sig is first 4 bytes of calldata, so we can use calldataload(0) with a mask\n or(\n // or operator sets sig_ in first 4 bytes with rest of bytes32 having default value of _SIG_SLOT_BASE\n _SIG_SLOT_BASE,\n and(calldataload(0), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)\n )\n )\n }\n\n if (implementation_ == address(0)) {\n revert FluidInfiniteProxyError(ErrorTypes.InfiniteProxy__ImplementationNotExist);\n }\n\n // Delegate the current call to `implementation`.\n // This does not return to its internall call site, it will return directly to the external caller.\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n if eq(result, 0) {\n // delegatecall returns 0 on error.\n revert(0, returndatasize())\n }\n\n return(0, returndatasize())\n }\n }\n\n receive() external payable {\n // receive method can never have calldata in EVM so no need for any logic here\n }\n}\n"
},
"contracts/libraries/bigMathMinified.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.\n/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision\n/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can\n/// result in significant gas cost reduction due to storage space reduction.\n/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.\n/// @dev roundUp is more like a increase 1, which happens everytime for the same number.\n/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.\nlibrary BigMathMinified {\n /// @dev constants to use for `roundUp` input param to increase readability\n bool internal constant ROUND_DOWN = false;\n bool internal constant ROUND_UP = true;\n\n /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).\n /// e.g.:\n /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]\n /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)\n /// => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000\n /// ^-------------------- 51(exponent) -------------- ^\n /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011 (2236301563)\n /// exponent = 0011,0011 (51)\n /// bigNumber = 1000,0101,0100,1011,0100,0000,1111,1011,0011,0011 (572493200179)\n ///\n /// @param normal number which needs to be converted into Big Number\n /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))\n /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))\n /// @param roundUp signals if result should be rounded down or up\n /// @return bigNumber converted bigNumber (coefficient << exponent)\n function toBigNumber(\n uint256 normal,\n uint256 coefficientSize,\n uint256 exponentSize,\n bool roundUp\n ) internal pure returns (uint256 bigNumber) {\n assembly {\n let lastBit_\n let number_ := normal\n if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit_ := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit_ := add(lastBit_, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit_ := add(lastBit_, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit_ := add(lastBit_, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit_ := add(lastBit_, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit_ := add(lastBit_, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit_ := add(lastBit_, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit_ := add(lastBit_, 1)\n }\n if gt(number_, 0) {\n lastBit_ := add(lastBit_, 1)\n }\n if lt(lastBit_, coefficientSize) {\n // for throw exception\n lastBit_ := coefficientSize\n }\n let exponent := sub(lastBit_, coefficientSize)\n let coefficient := shr(exponent, normal)\n if and(roundUp, gt(exponent, 0)) {\n // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number\n coefficient := add(coefficient, 1)\n if eq(shl(coefficientSize, 1), coefficient) {\n // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits\n // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.\n coefficient := shl(sub(coefficientSize, 1), 1)\n exponent := add(exponent, 1)\n }\n }\n if iszero(lt(exponent, shl(exponentSize, 1))) {\n // if exponent is >= exponentSize, the normal number is too big to fit within\n // BigNumber with too small sizes for coefficient and exponent\n revert(0, 0)\n }\n bigNumber := shl(exponentSize, coefficient)\n bigNumber := add(bigNumber, exponent)\n }\n }\n\n /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`\n function fromBigNumber(\n uint256 bigNumber,\n uint256 exponentSize,\n uint256 exponentMask\n ) internal pure returns (uint256 normal) {\n assembly {\n let coefficient := shr(exponentSize, bigNumber)\n let exponent := and(bigNumber, exponentMask)\n normal := shl(exponent, coefficient)\n }\n }\n\n /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).\n /// e.g.\n /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111\n /// lastBit = ^--------------------------------- 83 ----------------------------------------^\n function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {\n assembly {\n let number_ := normal\n if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit := add(lastBit, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit := add(lastBit, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit := add(lastBit, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit := add(lastBit, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit := add(lastBit, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit := add(lastBit, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit := add(lastBit, 1)\n }\n if gt(number_, 0) {\n lastBit := add(lastBit, 1)\n }\n }\n }\n}\n"
},
"contracts/libraries/bigMathVault.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { BigMathMinified } from \"./bigMathMinified.sol\";\n\n/// @title Extended version of BigMathMinified. Implements functions for normal operators (*, /, etc) modified to interact with big numbers.\n/// @notice this is an optimized version mainly created by taking Fluid vault's codebase into consideration so it's use is limited for other cases.\n// \n// @dev IMPORTANT: for any change here, make sure to uncomment and run the fuzz tests in bigMathVault.t.sol\nlibrary BigMathVault {\n uint private constant COEFFICIENT_SIZE_DEBT_FACTOR = 35;\n uint private constant EXPONENT_SIZE_DEBT_FACTOR = 15;\n uint private constant COEFFICIENT_MAX_DEBT_FACTOR = (1 << COEFFICIENT_SIZE_DEBT_FACTOR) - 1;\n uint private constant EXPONENT_MAX_DEBT_FACTOR = (1 << EXPONENT_SIZE_DEBT_FACTOR) - 1;\n uint private constant DECIMALS_DEBT_FACTOR = 16384;\n uint internal constant MAX_MASK_DEBT_FACTOR = (1 << (COEFFICIENT_SIZE_DEBT_FACTOR + EXPONENT_SIZE_DEBT_FACTOR)) - 1;\n\n // Having precision as 2**64 on vault\n uint internal constant PRECISION = 64;\n uint internal constant TWO_POWER_64 = 1 << PRECISION;\n // Max bit for 35 bits * 35 bits number will be 70\n // why do we use 69 then here instead of 70\n uint internal constant TWO_POWER_69_MINUS_1 = (1 << 69) - 1;\n\n uint private constant COEFFICIENT_PLUS_PRECISION = COEFFICIENT_SIZE_DEBT_FACTOR + PRECISION; // 99\n uint private constant COEFFICIENT_PLUS_PRECISION_MINUS_1 = COEFFICIENT_PLUS_PRECISION - 1; // 98\n uint private constant TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1 = (1 << COEFFICIENT_PLUS_PRECISION_MINUS_1) - 1; // (1 << 98) - 1;\n uint private constant TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1_MINUS_1 =\n (1 << (COEFFICIENT_PLUS_PRECISION_MINUS_1 - 1)) - 1; // (1 << 97) - 1;\n\n /// @dev multiplies a `normal` number with a `bigNumber1` and then divides by `bigNumber2`.\n /// @dev For vault's use case MUST always:\n /// - bigNumbers have exponent size 15 bits\n /// - bigNumbers have coefficient size 35 bits and have 35th bit always 1 (when exponent > 0 BigMath numbers have max precision)\n /// so coefficients must always be in range 17179869184 <= coefficient <= 34359738367.\n /// - bigNumber1 (debt factor) always have exponent >= 1 & <= 16384\n /// - bigNumber2 (connection factor) always have exponent >= 1 & <= 32767 (15 bits)\n /// - bigNumber2 always >= bigNumber1 (connection factor can never be < base branch debt factor)\n /// - as a result of previous points, numbers must never be 0\n /// - normal is positionRawDebt and is always within 10000 and type(int128).max\n /// @return normal * bigNumber1 / bigNumber2\n function mulDivNormal(uint256 normal, uint256 bigNumber1, uint256 bigNumber2) internal pure returns (uint256) {\n unchecked {\n // exponent2_ - exponent1_\n uint netExponent_ = (bigNumber2 & EXPONENT_MAX_DEBT_FACTOR) - (bigNumber1 & EXPONENT_MAX_DEBT_FACTOR);\n if (netExponent_ < 129) {\n // (normal * coefficient1_) / (coefficient2_ << netExponent_);\n return ((normal * (bigNumber1 >> EXPONENT_SIZE_DEBT_FACTOR)) /\n ((bigNumber2 >> EXPONENT_SIZE_DEBT_FACTOR) << netExponent_));\n }\n // else:\n // biggest possible nominator: type(int128).max * 35bits max = 5846006549323611672814739330865132078589370433536\n // smallest possible denominator: 17179869184 << 129 (= 1 << 163) = 11692013098647223345629478661730264157247460343808\n // -> can only ever be 0\n return 0;\n }\n }\n\n /// @dev multiplies a `bigNumber` with normal `number1` and then divides by `TWO_POWER_64`.\n /// @dev For vault's use case (calculating new branch debt factor after liquidation):\n /// - number1 is debtFactor, intialized as TWO_POWER_64 and reduced from there, hence it's always <= TWO_POWER_64 and always > 0.\n /// - bigNumber is branch debt factor, which starts as ((X35 << 15) | (1 << 14)) and reduces from there.\n /// - bigNumber must have have exponent size 15 bits and be >= 1 & <= 16384\n /// - bigNumber must have coefficient size 35 bits and have 35th bit always 1 (when exponent > 0 BigMath numbers have max precision)\n /// so coefficients must always be in range 17179869184 <= coefficient <= 34359738367.\n /// @param bigNumber Coefficient | Exponent.\n /// @param number1 normal number.\n /// @return result bigNumber * number1 / TWO_POWER_64.\n function mulDivBigNumber(uint256 bigNumber, uint256 number1) internal pure returns (uint256 result) {\n // using unchecked as we are only at 1 place in Vault and it won't overflow there.\n unchecked {\n uint256 _resultNumerator = (bigNumber >> EXPONENT_SIZE_DEBT_FACTOR) * number1; // bigNumber coefficient * normal number\n // 99% chances are that most sig bit should be 64 + 35 - 1 or 64 + 35 - 2\n // diff = mostSigBit. Can only ever be >= 35 and <= 98\n uint256 diff = (_resultNumerator > TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1)\n ? COEFFICIENT_PLUS_PRECISION\n : (_resultNumerator > TWO_POWER_COEFFICIENT_PLUS_PRECISION_MINUS_1_MINUS_1)\n ? COEFFICIENT_PLUS_PRECISION_MINUS_1\n : BigMathMinified.mostSignificantBit(_resultNumerator);\n\n // diff = difference in bits to make the _resultNumerator 35 bits again\n diff = diff - COEFFICIENT_SIZE_DEBT_FACTOR;\n _resultNumerator = _resultNumerator >> diff;\n // starting exponent is 16384, so exponent should never get 0 here\n result = (bigNumber & EXPONENT_MAX_DEBT_FACTOR) + diff;\n if (result > PRECISION) {\n result = (_resultNumerator << EXPONENT_SIZE_DEBT_FACTOR) + result - PRECISION; // divides by TWO_POWER_64 by reducing exponent by 64\n } else {\n // if number1 is small, e.g. 1e4 and bigNumber is also small e.g. coefficient = 17179869184 & exponent is at 50\n // then: resultNumerator = 171798691840000, diff most significant bit = 48, ending up with diff = 13\n // for exponent in result we end up doing: 50 + 13 - 64 -> underflowing exponent.\n // this should never happen anyway, but if it does better to revert than to continue with unknown effects.\n revert(); // debt factor should never become a BigNumber with exponent <= 0\n }\n }\n }\n\n /// @dev multiplies a `bigNumber1` with another `bigNumber2`.\n /// @dev For vault's use case (calculating connection factor of merged branches userTickDebtFactor * connectionDebtFactor *... connectionDebtFactor):\n /// - bigNumbers must have have exponent size 15 bits and be >= 1 & <= 32767\n /// - bigNumber must have coefficient size 35 bits and have 35th bit always 1 (when exponent > 0 BigMath numbers have max precision)\n /// so coefficients must always be in range 17179869184 <= coefficient <= 34359738367.\n /// @dev sum of exponents from `bigNumber1` `bigNumber2` should be > 16384.\n /// e.g. res = bigNumber1 * bigNumber2 = [(coe1, exp1) * (coe2, exp2)] >> decimal\n /// = (coe1*coe2>>overflow, exp1+exp2+overflow-decimal)\n /// @param bigNumber1 BigNumber format with coefficient and exponent.\n /// @param bigNumber2 BigNumber format with coefficient and exponent.\n /// @return BigNumber format with coefficient and exponent\n function mulBigNumber(uint256 bigNumber1, uint256 bigNumber2) internal pure returns (uint256) {\n unchecked {\n // coefficient1_ * coefficient2_\n uint resCoefficient_ = (bigNumber1 >> EXPONENT_SIZE_DEBT_FACTOR) *\n (bigNumber2 >> EXPONENT_SIZE_DEBT_FACTOR);\n // res coefficient at min can be 17179869184 * 17179869184 = 295147905179352825856 (= 1 << 68; 69th bit as 1)\n // res coefficient at max can be 34359738367 * 34359738367 = 1180591620648691826689 (X35 * X35 fits in 70 bits)\n uint overflowLen_ = resCoefficient_ > TWO_POWER_69_MINUS_1\n ? COEFFICIENT_SIZE_DEBT_FACTOR\n : COEFFICIENT_SIZE_DEBT_FACTOR - 1;\n // overflowLen_ is either 34 or 35\n resCoefficient_ = resCoefficient_ >> overflowLen_;\n\n // bigNumber2 is connection factor\n // exponent1_ + exponent2_ + overflowLen_ - decimals\n uint resExponent_ = ((bigNumber1 & EXPONENT_MAX_DEBT_FACTOR) +\n (bigNumber2 & EXPONENT_MAX_DEBT_FACTOR) +\n overflowLen_);\n if (resExponent_ < DECIMALS_DEBT_FACTOR) {\n // for this ever to happen, the debt factors used to calculate connection factors would have to be at extremely\n // unrealistic values. Like e.g.\n // branch3 (debt factor X35 << 15 | 16383) got merged into branch2 (debt factor X35 << 15 | 8190)\n // -> connection factor (divBigNumber): ((coe1<<precision_)/coe2>>overflowLen, exp1+decimal+overflowLen-exp2-precision_) so:\n // coefficient: (X35<<64)/X35 >> 30 = 17179869184\n // exponent: 8190+16384+30-16383-64 = 8157.\n // result: 17179869184 << 15 | 8157\n // and then branch2 into branch1 (debt factor X35 << 15 | 22). -> connection factor:\n // coefficient: (X35<<64)/X35 >> 30 = 17179869184\n // exponent: 22+16384+30-8190-64 = 8182.\n // result: 17179869184 << 15 | 8182\n // connection factors sum up (mulBigNumber): (coe1*coe2>>overflow, exp1+exp2+overflow-decimal)\n // exponent: 8182+8157+35-16384=16374-16384=-10. underflow.\n // this should never happen anyway, but if it does better to revert than to continue with unknown effects.\n revert();\n }\n resExponent_ = resExponent_ - DECIMALS_DEBT_FACTOR;\n\n if (resExponent_ > EXPONENT_MAX_DEBT_FACTOR) {\n // if resExponent_ is not within limits that means user's got ~100% (something like 99.999999999999...)\n // this situation will probably never happen and this basically means user's position is ~100% liquidated\n return MAX_MASK_DEBT_FACTOR;\n }\n\n return ((resCoefficient_ << EXPONENT_SIZE_DEBT_FACTOR) | resExponent_);\n }\n }\n\n /// @dev divides a `bigNumber1` by `bigNumber2`.\n /// @dev For vault's use case (calculating connectionFactor_ = baseBranchDebtFactor / currentBranchDebtFactor) bigNumbers MUST always:\n /// - have exponent size 15 bits and be >= 1 & <= 16384\n /// - have coefficient size 35 bits and have 35th bit always 1 (when exponent > 0 BigMath numbers have max precision)\n /// so coefficients must always be in range 17179869184 <= coefficient <= 34359738367.\n /// - as a result of previous points, numbers must never be 0\n /// e.g. res = bigNumber1 / bigNumber2 = [(coe1, exp1) / (coe2, exp2)] << decimal\n /// = ((coe1<<precision_)/coe2, exp1+decimal-exp2-precision_)\n /// @param bigNumber1 BigNumber format with coefficient and exponent\n /// @param bigNumber2 BigNumber format with coefficient and exponent\n /// @return BigNumber format with coefficient and exponent\n /// Returned connection factor can only ever be >= baseBranchDebtFactor (c = x*100/y with both x,y > 0 & x,y <= 100: c can only ever be >= x)\n function divBigNumber(uint256 bigNumber1, uint256 bigNumber2) internal pure returns (uint256) {\n unchecked {\n // (coefficient1_ << PRECISION) / coefficient2_\n uint256 resCoefficient_ = ((bigNumber1 >> EXPONENT_SIZE_DEBT_FACTOR) << PRECISION) /\n (bigNumber2 >> EXPONENT_SIZE_DEBT_FACTOR);\n // nominator at min 17179869184 << 64 = 316912650057057350374175801344. at max 34359738367 << 64 = 633825300095667956674642051072.\n // so min value resCoefficient_ 9223372037123211264 (64 bits) vs max 36893488146345361408 (fits in 65 bits)\n\n // mostSigBit will be PRECISION + 1 or PRECISION\n uint256 overflowLen_ = ((resCoefficient_ >> PRECISION) == 1) ? (PRECISION + 1) : PRECISION;\n // Overflow will be PRECISION - COEFFICIENT_SIZE_DEBT_FACTOR or (PRECISION + 1) - COEFFICIENT_SIZE_DEBT_FACTOR\n // Meaning 64 - 35 = 29 or 65 - 35 = 30\n overflowLen_ = overflowLen_ - COEFFICIENT_SIZE_DEBT_FACTOR;\n resCoefficient_ = resCoefficient_ >> overflowLen_;\n\n // exponent1_ will always be less than or equal to 16384\n // exponent2_ will always be less than or equal to 16384\n // Even if exponent2_ is 0 (not possible) & resExponent_ = DECIMALS_DEBT_FACTOR then also resExponent_ will be less than max limit, so no overflow\n // result exponent = (exponent1_ + DECIMALS_DEBT_FACTOR + overflowLen_) - (exponent2_ + PRECISION);\n uint256 resExponent_ = ((bigNumber1 & EXPONENT_MAX_DEBT_FACTOR) + // exponent1_\n DECIMALS_DEBT_FACTOR + // DECIMALS_DEBT_FACTOR is 100% as it is percentage value\n overflowLen_); // addition part resExponent_ here min 16414, max 32798\n // reuse overFlowLen_ variable for subtraction sum of exponent\n overflowLen_ = (bigNumber2 & EXPONENT_MAX_DEBT_FACTOR) + PRECISION; // subtraction part overflowLen_ here: min 65, max 16448\n if (resExponent_ > overflowLen_) {\n resExponent_ = resExponent_ - overflowLen_;\n\n return ((resCoefficient_ << EXPONENT_SIZE_DEBT_FACTOR) | resExponent_);\n }\n\n // Can happen if bigNumber1 exponent is < 35 (35+16384+29 = 16448) and bigNumber2 exponent is e.g. max 16384.\n // this would mean a branch with a normal big debt factor (bigNumber2) is merged into a base branch with an extremely small\n // debt factor (bigNumber1).\n // this should never happen anyway, but if it does better to revert than to continue with unknown effects.\n revert(); // connection factor should never become a BigNumber with exponent <= 0\n }\n }\n}\n"
},
"contracts/libraries/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary LibsErrorTypes {\n /***********************************|\n | LiquidityCalcs | \n |__________________________________*/\n\n /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)\n uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;\n\n /// @notice thrown when rate data is set to a version that is not implemented\n uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;\n\n /// @notice thrown when the calculated borrow rate turns negative. This should never happen.\n uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;\n\n /***********************************|\n | SafeTransfer | \n |__________________________________*/\n\n /// @notice thrown when safe transfer from for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFromFailed = 71001;\n\n /// @notice thrown when safe transfer for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFailed = 71002;\n}\n"
},
"contracts/libraries/liquidityCalcs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { LibsErrorTypes as ErrorTypes } from \"./errorTypes.sol\";\nimport { LiquiditySlotsLink } from \"./liquiditySlotsLink.sol\";\nimport { BigMathMinified } from \"./bigMathMinified.sol\";\n\n/// @notice implements calculation methods used for Fluid liquidity such as updated exchange prices,\n/// borrow rate, withdrawal / borrow limits, revenue amount.\nlibrary LiquidityCalcs {\n error FluidLiquidityCalcsError(uint256 errorId_);\n\n /// @notice emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535\n event BorrowRateMaxCap();\n\n /// @dev constants as from Liquidity variables.sol\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n /// @dev Ignoring leap years\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n // constants used for BigMath conversion from and to storage\n uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\n\n uint256 internal constant FOUR_DECIMALS = 1e4;\n uint256 internal constant TWELVE_DECIMALS = 1e12;\n uint256 internal constant X14 = 0x3fff;\n uint256 internal constant X15 = 0x7fff;\n uint256 internal constant X16 = 0xffff;\n uint256 internal constant X18 = 0x3ffff;\n uint256 internal constant X24 = 0xffffff;\n uint256 internal constant X33 = 0x1ffffffff;\n uint256 internal constant X64 = 0xffffffffffffffff;\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC EXCHANGE PRICES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates interest (exchange prices) for a token given its' exchangePricesAndConfig from storage.\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @return supplyExchangePrice_ updated supplyExchangePrice\n /// @return borrowExchangePrice_ updated borrowExchangePrice\n function calcExchangePrices(\n uint256 exchangePricesAndConfig_\n ) internal view returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {\n // Extracting exchange prices\n supplyExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &\n X64;\n borrowExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &\n X64;\n\n if (supplyExchangePrice_ == 0 || borrowExchangePrice_ == 0) {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__ExchangePriceZero);\n }\n\n uint256 temp_ = exchangePricesAndConfig_ & X16; // temp_ = borrowRate\n\n unchecked {\n // last timestamp can not be > current timestamp\n uint256 secondsSinceLastUpdate_ = block.timestamp -\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33);\n\n uint256 borrowRatio_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\n X15;\n if (secondsSinceLastUpdate_ == 0 || temp_ == 0 || borrowRatio_ == 1) {\n // if no time passed, borrow rate is 0, or no raw borrowings: no exchange price update needed\n // (if borrowRatio_ == 1 means there is only borrowInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // calculate new borrow exchange price.\n // formula borrowExchangePriceIncrease: previous price * borrow rate * secondsSinceLastUpdate_.\n // nominator is max uint112 (uint64 * uint16 * uint32). Divisor can not be 0.\n borrowExchangePrice_ +=\n (borrowExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS);\n\n // FOR SUPPLY EXCHANGE PRICE:\n // all yield paid by borrowers (in mode with interest) goes to suppliers in mode with interest.\n // formula: previous price * supply rate * secondsSinceLastUpdate_.\n // where supply rate = (borrow rate - revenueFee%) * ratioSupplyYield. And\n // ratioSupplyYield = utilization * supplyRatio * borrowRatio\n //\n // Example:\n // supplyRawInterest is 80, supplyInterestFree is 20. totalSupply is 100. BorrowedRawInterest is 50.\n // BorrowInterestFree is 10. TotalBorrow is 60. borrow rate 40%, revenueFee 10%.\n // yield is 10 (so half a year must have passed).\n // supplyRawInterest must become worth 89. totalSupply must become 109. BorrowedRawInterest must become 60.\n // borrowInterestFree must still be 10. supplyInterestFree still 20. totalBorrow 70.\n // supplyExchangePrice would have to go from 1 to 1,125 (+ 0.125). borrowExchangePrice from 1 to 1,2 (+0.2).\n // utilization is 60%. supplyRatio = 20 / 80 = 25% (only 80% of lenders receiving yield).\n // borrowRatio = 10 / 50 = 20% (only 83,333% of borrowers paying yield):\n // x of borrowers paying yield = 100% - (20 / (100 + 20)) = 100% - 16.6666666% = 83,333%.\n // ratioSupplyYield = 60% * 83,33333% * (100% + 20%) = 62,5%\n // supplyRate = (40% * (100% - 10%)) * = 36% * 62,5% = 22.5%\n // increase in supplyExchangePrice, assuming 100 as previous price.\n // 100 * 22,5% * 1/2 (half a year) = 0,1125.\n // cross-check supplyRawInterest worth = 80 * 1.1125 = 89. totalSupply worth = 89 + 20.\n\n // -------------- 1. calculate ratioSupplyYield --------------------------------\n // step1: utilization * supplyRatio (or actually part of lenders receiving yield)\n\n // temp_ => supplyRatio (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n // if first bit 0 then ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n // else ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & X15;\n\n if (temp_ == 1) {\n // if no raw supply: no exchange price update needed\n // (if supplyRatio_ == 1 means there is only supplyInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // ratioSupplyYield precision is 1e27 as 100% for increased precision when supplyInterestFree > supplyWithInterest\n if (temp_ & 1 == 1) {\n // ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = temp_ >> 1;\n\n // Note: case where temp_ == 0 (only supplyInterestFree, no yield) already covered by early return\n // in the if statement a little above.\n\n // based on above example but supplyRawInterest is 20, supplyInterestFree is 80. no fee.\n // supplyRawInterest must become worth 30. totalSupply must become 110.\n // supplyExchangePrice would have to go from 1 to 1,5. borrowExchangePrice from 1 to 1,2.\n // so ratioSupplyYield must come out as 2.5 (250%).\n // supplyRatio would be (20 * 10_000 / 80) = 2500. but must be inverted.\n temp_ = (1e27 * FOUR_DECIMALS) / temp_; // e.g. 1e31 / 2500 = 4e27. (* 1e27 for precision)\n // e.g. 5_000 * (1e27 + 4e27) / 1e27 = 25_000 (=250%).\n temp_ =\n // utilization * (100% + 100% / supplyRatio)\n (((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) *\n (1e27 + temp_)) / // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS);\n // max possible value of temp_ here is 16383 * (1e27 + 1e31) / 1e4 = ~1.64e31\n } else {\n // ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n temp_ = temp_ >> 1;\n // if temp_ == 0 then only supplyWithInterest => full yield. temp_ is already 0\n\n // e.g. 5_000 * 10_000 + (20 * 10_000 / 80) / 10_000 = 5000 * 12500 / 10000 = 6250 (=62.5%).\n temp_ =\n // 1e27 * utilization * (100% + supplyRatio) / 100%\n (1e27 *\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) * // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS + temp_)) /\n (FOUR_DECIMALS * FOUR_DECIMALS);\n // max possible temp_ value: 1e27 * 16383 * 2e4 / 1e8 = 3.2766e27\n }\n // from here temp_ => ratioSupplyYield (utilization * supplyRatio part) scaled by 1e27. max possible value ~1.64e31\n\n // step2 of ratioSupplyYield: add borrowRatio (only x% of borrowers paying yield)\n if (borrowRatio_ & 1 == 1) {\n // ratio is borrowWithInterest / borrowInterestFree (borrowInterestFree is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n\n // Note: case where borrowRatio_ == 0 (only borrowInterestFree, no yield) already covered\n // at the beginning of the method by early return if `borrowRatio_ == 1`.\n\n // based on above example but borrowRawInterest is 10, borrowInterestFree is 50. no fee. borrowRatio = 20%.\n // so only 16.66% of borrowers are paying yield. so the 100% - part of the formula is not needed.\n // x of borrowers paying yield = (borrowRatio / (100 + borrowRatio)) = 16.6666666%\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n borrowRatio_ = (borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_);\n // max value here for borrowRatio_ is (1e31 / (1e4 + 1e4))= 5e26 (= 50% of borrowers paying yield).\n } else {\n // ratio is borrowInterestFree / borrowWithInterest (borrowWithInterest is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n // x of borrowers paying yield = 100% - (borrowRatio / (100 + borrowRatio)) = 100% - 16.6666666% = 83,333%.\n borrowRatio_ = (1e27 - ((borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_)));\n // borrowRatio can never be > 100%. so max subtraction can be 100% - 100% / 200%.\n // or if borrowRatio_ is 0 -> 100% - 0. or if borrowRatio_ is 1 -> 100% - 1 / 101.\n // max value here for borrowRatio_ is 1e27 - 0 = 1e27 (= 100% of borrowers paying yield).\n }\n\n // temp_ => ratioSupplyYield. scaled down from 1e25 = 1% each to normal percent precision 1e2 = 1%.\n // max nominator value is ~1.64e31 * 1e27 = 1.64e58. max result = 1.64e8\n temp_ = (FOUR_DECIMALS * temp_ * borrowRatio_) / 1e54;\n\n // 2. calculate supply rate\n // temp_ => supply rate (borrow rate - revenueFee%) * ratioSupplyYield.\n // division part is done in next step to increase precision. (divided by 2x FOUR_DECIMALS, fee + borrowRate)\n // Note that all calculation divisions for supplyExchangePrice are rounded down.\n // Note supply rate can be bigger than the borrowRate, e.g. if there are only few lenders with interest\n // but more suppliers not earning interest.\n temp_ = ((exchangePricesAndConfig_ & X16) * // borrow rate\n temp_ * // ratioSupplyYield\n (FOUR_DECIMALS - ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14))); // revenueFee\n // fee can not be > 100%. max possible = 65535 * ~1.64e8 * 1e4 =~1.074774e17.\n\n // 3. calculate increase in supply exchange price\n supplyExchangePrice_ += ((supplyExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS * FOUR_DECIMALS * FOUR_DECIMALS));\n // max possible nominator = max uint 64 * 1.074774e17 * max uint32 = ~8.52e45. Denominator can not be 0.\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC REVENUE /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev gets the `revenueAmount_` for a token given its' totalAmounts and exchangePricesAndConfig from storage\n /// and the current balance of the Fluid liquidity contract for the token.\n /// @param totalAmounts_ total amounts packed uint256 read from storage\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @param liquidityTokenBalance_ current balance of Liquidity contract (IERC20(token_).balanceOf(address(this)))\n /// @return revenueAmount_ collectable revenue amount\n function calcRevenue(\n uint256 totalAmounts_,\n uint256 exchangePricesAndConfig_,\n uint256 liquidityTokenBalance_\n ) internal view returns (uint256 revenueAmount_) {\n // @dev no need to super-optimize this method as it is only used by admin\n\n // calculate the new exchange prices based on earned interest\n (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = calcExchangePrices(exchangePricesAndConfig_);\n\n // total supply = interest free + with interest converted from raw\n uint256 totalSupply_ = getTotalSupply(totalAmounts_, supplyExchangePrice_);\n\n if (totalSupply_ > 0) {\n // available revenue: balanceOf(token) + totalBorrowings - totalLendings.\n revenueAmount_ = liquidityTokenBalance_ + getTotalBorrow(totalAmounts_, borrowExchangePrice_);\n // ensure there is no possible case because of rounding etc. where this would revert,\n // explicitly check if >\n revenueAmount_ = revenueAmount_ > totalSupply_ ? revenueAmount_ - totalSupply_ : 0;\n // Note: if utilization > 100% (totalSupply < totalBorrow), then all the amount above 100% utilization\n // can only be revenue.\n } else {\n // if supply is 0, then rest of balance can be withdrawn as revenue so that no amounts get stuck\n revenueAmount_ = liquidityTokenBalance_;\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC LIMITS /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates withdrawal limit before an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath\n /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitBeforeOperate(\n uint256 userSupplyData_,\n uint256 userSupply_\n ) internal view returns (uint256 currentWithdrawalLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).\n // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.\n // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be\n // a deposit anyway. Important is that it would not revert.\n\n // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit\n // is the fully expanded limit immediately.\n\n // extract last set withdrawal limit\n uint256 lastWithdrawalLimit_ = (userSupplyData_ >>\n LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) & X64;\n lastWithdrawalLimit_ =\n (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);\n if (lastWithdrawalLimit_ == 0) {\n // withdrawal limit is not activated. Max withdrawal allowed\n return 0;\n }\n\n uint256 maxWithdrawableLimit_;\n uint256 temp_;\n unchecked {\n // extract max withdrawable percent of user supply and\n // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed\n // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.\n\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxWithdrawableLimit_ =\n (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /\n FOUR_DECIMALS;\n\n // time elapsed since last withdrawal limit was set (in seconds)\n // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.\n // last timestamp can not be > current timestamp\n temp_ =\n block.timestamp -\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);\n }\n // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.\n // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.\n // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.\n temp_ =\n (maxWithdrawableLimit_ * temp_) /\n // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0\n // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.\n // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,\n // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0\n // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.\n unchecked {\n // underflow explicitly checked & handled\n currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;\n // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - maxWithdrawableLimit_;\n }\n // if withdrawal limit is decreased below minimum then set minimum\n // (e.g. when more than expandDuration time has elapsed)\n if (temp_ > currentWithdrawalLimit_) {\n currentWithdrawalLimit_ = temp_;\n }\n }\n\n /// @dev calculates withdrawal limit after an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount\n /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`\n /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitAfterOperate(\n uint256 userSupplyData_,\n uint256 userSupply_,\n uint256 newWithdrawalLimit_\n ) internal pure returns (uint256) {\n // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed\n uint256 temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // if user supply is below base limit then max withdrawals are allowed\n if (userSupply_ < temp_) {\n return 0;\n }\n // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)\n temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;\n unchecked {\n // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);\n }\n // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.\n // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where\n // increased deposit amount outpaces withrawals.\n if (temp_ > newWithdrawalLimit_) {\n return temp_;\n }\n return newWithdrawalLimit_;\n }\n\n /// @dev calculates borrow limit before an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`\n /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitBeforeOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_\n ) internal view returns (uint256 currentBorrowLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.\n // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus\n // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.\n\n // temp_ = extract borrow expand percent (is in 1e2 decimals)\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;\n\n uint256 maxExpansionLimit_;\n uint256 maxExpandedBorrowLimit_;\n unchecked {\n // calculate max expansion limit: Max amount limit can expand to since last interaction\n // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);\n\n // calculate max borrow limit: Max point limit can increase to since last interaction\n maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;\n }\n\n // currentBorrowLimit_ = extract base borrow limit\n currentBorrowLimit_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n currentBorrowLimit_ =\n (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);\n\n if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {\n return currentBorrowLimit_;\n }\n // time elapsed since last borrow limit was set (in seconds)\n unchecked {\n // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)\n temp_ =\n block.timestamp -\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last update timestamp\n }\n\n // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit\n currentBorrowLimit_ =\n // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.\n // divisor is extract expand duration (after this, full expansion to expandPercentage happened).\n ((maxExpansionLimit_ * temp_) /\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0\n // extract last set borrow limit\n BigMathMinified.fromBigNumber(\n (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,\n // so set to `maxExpandedBorrowLimit_` in that case.\n // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)\n if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {\n currentBorrowLimit_ = maxExpandedBorrowLimit_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (currentBorrowLimit_ > temp_) {\n currentBorrowLimit_ = temp_;\n }\n }\n\n /// @dev calculates borrow limit after an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount\n /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`\n /// @return borrowLimit_ updated borrow limit that should be written to storage.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitAfterOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_,\n uint256 newBorrowLimit_\n ) internal pure returns (uint256 borrowLimit_) {\n // temp_ = extract borrow expand percent\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)\n\n unchecked {\n // borrowLimit_ = calculate maximum borrow limit at full expansion.\n // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);\n }\n\n // temp_ = extract base borrow limit\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (borrowLimit_ < temp_) {\n // below base limit, borrow limit is always base limit\n return temp_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // make sure fully expanded borrow limit is not above hard max borrow limit\n if (borrowLimit_ > temp_) {\n borrowLimit_ = temp_;\n }\n // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.\n // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)\n if (newBorrowLimit_ > borrowLimit_) {\n return borrowLimit_;\n }\n return newBorrowLimit_;\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC RATES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev Calculates new borrow rate from utilization for a token\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ totalBorrow / totalSupply. 1e4 = 100% utilization\n /// @return rate_ rate for that particular token in 1e2 precision (e.g. 5% rate = 500)\n function calcBorrowRateFromUtilization(uint256 rateData_, uint256 utilization_) internal returns (uint256 rate_) {\n // extract rate version: 4 bits (0xF) starting from bit 0\n uint256 rateVersion_ = (rateData_ & 0xF);\n\n if (rateVersion_ == 1) {\n rate_ = calcRateV1(rateData_, utilization_);\n } else if (rateVersion_ == 2) {\n rate_ = calcRateV2(rateData_, utilization_);\n } else {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__UnsupportedRateVersion);\n }\n\n if (rate_ > X16) {\n // hard cap for borrow rate at maximum value 16 bits (65535) to make sure it does not overflow storage space.\n // this is unlikely to ever happen if configs stay within expected levels.\n rate_ = X16;\n // emit event to more easily become aware\n emit BorrowRateMaxCap();\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 1 (with one kink) in 1e2 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e2 precision\n function calcRateV1(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v1 (one kink) ------------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 188 bits => 68-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can also be negative for declining rates)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // else utilization is greater than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink1_;\n x2_ = FOUR_DECIMALS; // 100%\n }\n\n int256 constant_;\n int256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor)\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((x2_ - x1_));\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - (slope_ * int256(x1_));\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\n if (slope_ < 0) {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\n }\n rate_ = uint256(slope_) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 2 (with two kinks) in 1e4 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e4 precision\n function calcRateV2(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v2 (two kinks) -----------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Utilization at kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 68- 83 => Rate at utilization kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 84- 99 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 156 bits => 100-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can also be negative for declining rates)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink1\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // extract kink2: 16 bits (0xFFFF) starting from bit 52\n uint256 kink2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16;\n if (utilization_ < kink2_) {\n // if utilization is less than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n x1_ = kink1_;\n x2_ = kink2_;\n } else {\n // else utilization is greater than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink2_;\n x2_ = FOUR_DECIMALS;\n }\n }\n\n int256 constant_;\n int256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor)\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((x2_ - x1_));\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - (slope_ * int256(x1_));\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\n if (slope_ < 0) {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\n }\n rate_ = uint256(slope_) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev reads the total supply out of Liquidity packed storage `totalAmounts_` for `supplyExchangePrice_`\n function getTotalSupply(\n uint256 totalAmounts_,\n uint256 supplyExchangePrice_\n ) internal pure returns (uint256 totalSupply_) {\n // totalSupply_ => supplyInterestFree\n totalSupply_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n totalSupply_ = (totalSupply_ >> DEFAULT_EXPONENT_SIZE) << (totalSupply_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalSupplyRaw_ = totalAmounts_ & X64; // no shifting as supplyRaw is first 64 bits\n totalSupplyRaw_ = (totalSupplyRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalSupplyRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalSupply = supplyInterestFree + supplyRawInterest normalized from raw\n totalSupply_ += ((totalSupplyRaw_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n\n /// @dev reads the total borrow out of Liquidity packed storage `totalAmounts_` for `borrowExchangePrice_`\n function getTotalBorrow(\n uint256 totalAmounts_,\n uint256 borrowExchangePrice_\n ) internal pure returns (uint256 totalBorrow_) {\n // totalBorrow_ => borrowInterestFree\n // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n totalBorrow_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n totalBorrow_ = (totalBorrow_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrow_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalBorrowRaw_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n totalBorrowRaw_ = (totalBorrowRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrowRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalBorrow = borrowInterestFree + borrowRawInterest normalized from raw\n totalBorrow_ += ((totalBorrowRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n}\n"
},
"contracts/libraries/liquiditySlotsLink.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice library that helps in reading / working with storage slot data of Fluid Liquidity.\n/// @dev as all data for Fluid Liquidity is internal, any data must be fetched directly through manual\n/// slot reading through this library or, if gas usage is less important, through the FluidLiquidityResolver.\nlibrary LiquiditySlotsLink {\n /// @dev storage slot for status at Liquidity\n uint256 internal constant LIQUIDITY_STATUS_SLOT = 1;\n /// @dev storage slot for auths mapping at Liquidity\n uint256 internal constant LIQUIDITY_AUTHS_MAPPING_SLOT = 2;\n /// @dev storage slot for guardians mapping at Liquidity\n uint256 internal constant LIQUIDITY_GUARDIANS_MAPPING_SLOT = 3;\n /// @dev storage slot for user class mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_CLASS_MAPPING_SLOT = 4;\n /// @dev storage slot for exchangePricesAndConfig mapping at Liquidity\n uint256 internal constant LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT = 5;\n /// @dev storage slot for rateData mapping at Liquidity\n uint256 internal constant LIQUIDITY_RATE_DATA_MAPPING_SLOT = 6;\n /// @dev storage slot for totalAmounts mapping at Liquidity\n uint256 internal constant LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT = 7;\n /// @dev storage slot for user supply double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT = 8;\n /// @dev storage slot for user borrow double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT = 9;\n /// @dev storage slot for listed tokens array at Liquidity\n uint256 internal constant LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT = 10;\n\n // --------------------------------\n // @dev stacked uint256 storage slots bits position data for each:\n\n // ExchangePricesAndConfig\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATE = 0;\n uint256 internal constant BITS_EXCHANGE_PRICES_FEE = 16;\n uint256 internal constant BITS_EXCHANGE_PRICES_UTILIZATION = 30;\n uint256 internal constant BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD = 44;\n uint256 internal constant BITS_EXCHANGE_PRICES_LAST_TIMESTAMP = 58;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE = 91;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE = 155;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATIO = 234;\n\n // RateData:\n uint256 internal constant BITS_RATE_DATA_VERSION = 0;\n // RateData: V1\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V1_UTILIZATION_AT_KINK = 20;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK = 36;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX = 52;\n // RateData: V2\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1 = 20;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1 = 36;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2 = 52;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2 = 68;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX = 84;\n\n // TotalAmounts\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_WITH_INTEREST = 0;\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE = 64;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST = 128;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE = 192;\n\n // UserSupplyData\n uint256 internal constant BITS_USER_SUPPLY_MODE = 0;\n uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;\n uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;\n uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;\n uint256 internal constant BITS_USER_SUPPLY_IS_PAUSED = 255;\n\n // UserBorrowData\n uint256 internal constant BITS_USER_BORROW_MODE = 0;\n uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;\n uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;\n uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;\n uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;\n uint256 internal constant BITS_USER_BORROW_IS_PAUSED = 255;\n\n // --------------------------------\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping at `slot_` for `key_`\n function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for double mapping at `slot_` for `key1_` and `key2_`\n function calculateDoubleMappingStorageSlot(\n uint256 slot_,\n address key1_,\n address key2_\n ) internal pure returns (bytes32) {\n bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n return keccak256(abi.encode(key2_, intermediateSlot_));\n }\n}\n"
},
"contracts/libraries/storageRead.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice implements a method to read uint256 data from storage at a bytes32 storage slot key.\ncontract StorageRead {\n function readFromStorage(bytes32 slot_) public view returns (uint256 result_) {\n assembly {\n result_ := sload(slot_) // read value from the storage slot\n }\n }\n}\n"
},
"contracts/libraries/storageReadVaultFactory.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice implements a method to read uint256 data from storage at a bytes32 storage slot key.\ncontract StorageRead {\n function readFromStorage(bytes32 slot_) public view returns (uint256 result_) {\n assembly {\n result_ := sload(slot_) // read value from the storage slot\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\n /// @notice struct to set user supply & withdrawal config\n struct UserSupplyConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which withdrawal limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration withdrawal limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseWithdrawalLimit;\n }\n\n /// @notice struct to set user borrow & payback config\n struct UserBorrowConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which debt limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration debt limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling\n /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseDebtCeiling;\n ///\n /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 maxDebtCeiling;\n }\n}\n"
},
"contracts/liquidity/interfaces/iLiquidity.sol": {
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IProxy } from \"../../infiniteProxy/interfaces/iProxy.sol\";\nimport { Structs as AdminModuleStructs } from \"../adminModule/structs.sol\";\n\ninterface IFluidLiquidityAdmin {\n /// @notice adds/removes auths. Auths generally could be contracts which can have restricted actions defined on contract.\n /// auths can be helpful in reducing governance overhead where it's not needed.\n /// @param authsStatus_ array of structs setting allowed status for an address.\n /// status true => add auth, false => remove auth\n function updateAuths(AdminModuleStructs.AddressBool[] calldata authsStatus_) external;\n\n /// @notice adds/removes guardians. Only callable by Governance.\n /// @param guardiansStatus_ array of structs setting allowed status for an address.\n /// status true => add guardian, false => remove guardian\n function updateGuardians(AdminModuleStructs.AddressBool[] calldata guardiansStatus_) external;\n\n /// @notice changes the revenue collector address (contract that is sent revenue). Only callable by Governance.\n /// @param revenueCollector_ new revenue collector address\n function updateRevenueCollector(address revenueCollector_) external;\n\n /// @notice changes current status, e.g. for pausing or unpausing all user operations. Only callable by Auths.\n /// @param newStatus_ new status\n /// status = 2 -> pause, status = 1 -> resume.\n function changeStatus(uint256 newStatus_) external;\n\n /// @notice update tokens rate data version 1. Only callable by Auths.\n /// @param tokensRateData_ array of RateDataV1Params with rate data to set for each token\n function updateRateDataV1s(AdminModuleStructs.RateDataV1Params[] calldata tokensRateData_) external;\n\n /// @notice update tokens rate data version 2. Only callable by Auths.\n /// @param tokensRateData_ array of RateDataV2Params with rate data to set for each token\n function updateRateDataV2s(AdminModuleStructs.RateDataV2Params[] calldata tokensRateData_) external;\n\n /// @notice updates token configs: fee charge on borrowers interest & storage update utilization threshold.\n /// Only callable by Auths.\n /// @param tokenConfigs_ contains token address, fee & utilization threshold\n function updateTokenConfigs(AdminModuleStructs.TokenConfig[] calldata tokenConfigs_) external;\n\n /// @notice updates user classes: 0 is for new protocols, 1 is for established protocols.\n /// Only callable by Auths.\n /// @param userClasses_ struct array of uint256 value to assign for each user address\n function updateUserClasses(AdminModuleStructs.AddressUint256[] calldata userClasses_) external;\n\n /// @notice sets user supply configs per token basis. Eg: with interest or interest-free and automated limits.\n /// Only callable by Auths.\n /// @param userSupplyConfigs_ struct array containing user supply config, see `UserSupplyConfig` struct for more info\n function updateUserSupplyConfigs(AdminModuleStructs.UserSupplyConfig[] memory userSupplyConfigs_) external;\n\n /// @notice setting user borrow configs per token basis. Eg: with interest or interest-free and automated limits.\n /// Only callable by Auths.\n /// @param userBorrowConfigs_ struct array containing user borrow config, see `UserBorrowConfig` struct for more info\n function updateUserBorrowConfigs(AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_) external;\n\n /// @notice pause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n /// Only callable by Guardians.\n /// @param user_ address of user to pause operations for\n /// @param supplyTokens_ token addresses to pause withdrawals for\n /// @param borrowTokens_ token addresses to pause borrowings for\n function pauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n /// @notice unpause operations for a particular user in class 0 (class 1 users can't be paused by guardians).\n /// Only callable by Guardians.\n /// @param user_ address of user to unpause operations for\n /// @param supplyTokens_ token addresses to unpause withdrawals for\n /// @param borrowTokens_ token addresses to unpause borrowings for\n function unpauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;\n\n /// @notice collects revenue for tokens to configured revenueCollector address.\n /// @param tokens_ array of tokens to collect revenue for\n /// @dev Note that this can revert if token balance is < revenueAmount (utilization > 100%)\n function collectRevenue(address[] calldata tokens_) external;\n\n /// @notice gets the current updated exchange prices for n tokens and updates all prices, rates related data in storage.\n /// @param tokens_ tokens to update exchange prices for\n /// @return supplyExchangePrices_ new supply rates of overall system for each token\n /// @return borrowExchangePrices_ new borrow rates of overall system for each token\n function updateExchangePrices(\n address[] calldata tokens_\n ) external returns (uint256[] memory supplyExchangePrices_, uint256[] memory borrowExchangePrices_);\n}\n\ninterface IFluidLiquidityLogic is IFluidLiquidityAdmin {\n /// @notice Single function which handles supply, withdraw, borrow & payback\n /// @param token_ address of token (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native)\n /// @param supplyAmount_ if +ve then supply, if -ve then withdraw, if 0 then nothing\n /// @param borrowAmount_ if +ve then borrow, if -ve then payback, if 0 then nothing\n /// @param withdrawTo_ if withdrawal then to which address\n /// @param borrowTo_ if borrow then to which address\n /// @param callbackData_ callback data passed to `liquidityCallback` method of protocol\n /// @return memVar3_ updated supplyExchangePrice\n /// @return memVar4_ updated borrowExchangePrice\n /// @dev to trigger skipping in / out transfers when in&out amounts balance themselves out (gas optimization):\n /// - supply(+) == borrow(+), withdraw(-) == payback(-).\n /// - `withdrawTo_` / `borrowTo_` must be msg.sender (protocol)\n /// - `callbackData_` MUST be encoded so that \"from\" address is at last 20 bytes (if this optimization is desired),\n /// also for native token operations where liquidityCallback is not triggered!\n /// from address must come at last position if there is more data. I.e. encode like:\n /// abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end\n /// so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end.\n function operate(\n address token_,\n int256 supplyAmount_,\n int256 borrowAmount_,\n address withdrawTo_,\n address borrowTo_,\n bytes calldata callbackData_\n ) external payable returns (uint256 memVar3_, uint256 memVar4_);\n}\n\ninterface IFluidLiquidity is IProxy, IFluidLiquidityLogic {}\n"
},
"contracts/liquidity/proxy.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Proxy } from \"../infiniteProxy/proxy.sol\";\n\n/// @notice Fluid Liquidity infinte proxy.\n/// Liquidity is the central point of the Instadapp Fluid architecture, it is the core interaction point\n/// for all allow-listed protocols, such as fTokens, Vault, Flashloan, StETH protocol, DEX protocol etc.\ncontract FluidLiquidityProxy is Proxy {\n constructor(address admin_, address dummyImplementation_) Proxy(admin_, dummyImplementation_) {}\n}\n"
},
"contracts/protocols/vault/error.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n error FluidVaultError(uint256 errorId_);\n\n /// @notice used to simulate liquidation to find the maximum liquidatable amounts\n error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);\n}\n"
},
"contracts/protocols/vault/errorTypes.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n /***********************************|\n | Vault Factory | \n |__________________________________*/\n\n uint256 internal constant VaultFactory__InvalidOperation = 30001;\n uint256 internal constant VaultFactory__Unauthorized = 30002;\n uint256 internal constant VaultFactory__SameTokenNotAllowed = 30003;\n uint256 internal constant VaultFactory__InvalidParams = 30004;\n uint256 internal constant VaultFactory__InvalidVault = 30005;\n uint256 internal constant VaultFactory__InvalidVaultAddress = 30006;\n uint256 internal constant VaultFactory__OnlyDelegateCallAllowed = 30007;\n\n /***********************************|\n | VaultT1 | \n |__________________________________*/\n\n /// @notice thrown at reentrancy\n uint256 internal constant VaultT1__AlreadyEntered = 31001;\n\n /// @notice thrown when user sends deposit & borrow amount as 0\n uint256 internal constant VaultT1__InvalidOperateAmount = 31002;\n\n /// @notice thrown when msg.value is not in sync with native token deposit or payback\n uint256 internal constant VaultT1__InvalidMsgValueOperate = 31003;\n\n /// @notice thrown when msg.sender is not the owner of the vault\n uint256 internal constant VaultT1__NotAnOwner = 31004;\n\n /// @notice thrown when user's position does not exist. Sending the wrong index from the frontend\n uint256 internal constant VaultT1__TickIsEmpty = 31005;\n\n /// @notice thrown when the user's position is above CF and the user tries to make it more risky by trying to withdraw or borrow\n uint256 internal constant VaultT1__PositionAboveCF = 31006;\n\n /// @notice thrown when the top tick is not initialized. Happens if the vault is totally new or all the user's left\n uint256 internal constant VaultT1__TopTickDoesNotExist = 31007;\n\n /// @notice thrown when msg.value in liquidate is not in sync payback\n uint256 internal constant VaultT1__InvalidMsgValueLiquidate = 31008;\n\n /// @notice thrown when slippage is more on liquidation than what the liquidator sent\n uint256 internal constant VaultT1__ExcessSlippageLiquidation = 31009;\n\n /// @notice thrown when msg.sender is not the rebalancer/reserve contract\n uint256 internal constant VaultT1__NotRebalancer = 31010;\n\n /// @notice thrown when NFT of one vault interacts with the NFT of other vault\n uint256 internal constant VaultT1__NftNotOfThisVault = 31011;\n\n /// @notice thrown when the token is not initialized on the liquidity contract\n uint256 internal constant VaultT1__TokenNotInitialized = 31012;\n\n /// @notice thrown when admin updates fallback if a non-auth calls vault\n uint256 internal constant VaultT1__NotAnAuth = 31013;\n\n /// @notice thrown in operate when user tries to witdhraw more collateral than deposited\n uint256 internal constant VaultT1__ExcessCollateralWithdrawal = 31014;\n\n /// @notice thrown in operate when user tries to payback more debt than borrowed\n uint256 internal constant VaultT1__ExcessDebtPayback = 31015;\n\n /// @notice thrown when user try to withdrawal more than operate's withdrawal limit\n uint256 internal constant VaultT1__WithdrawMoreThanOperateLimit = 31016;\n\n /// @notice thrown when caller of liquidityCallback is not Liquidity\n uint256 internal constant VaultT1__InvalidLiquidityCallbackAddress = 31017;\n\n /// @notice thrown when reentrancy is not already on\n uint256 internal constant VaultT1__NotEntered = 31018;\n\n /// @notice thrown when someone directly calls secondary implementation contract\n uint256 internal constant VaultT1__OnlyDelegateCallAllowed = 31019;\n\n /// @notice thrown when the safeTransferFrom for a token amount failed\n uint256 internal constant VaultT1__TransferFromFailed = 31020;\n\n /// @notice thrown when exchange price overflows while updating on storage\n uint256 internal constant VaultT1__ExchangePriceOverFlow = 31021;\n\n /// @notice thrown when debt to liquidate amt is sent wrong\n uint256 internal constant VaultT1__InvalidLiquidationAmt = 31022;\n\n /// @notice thrown when user debt or collateral goes above 2**128 or below -2**128\n uint256 internal constant VaultT1__UserCollateralDebtExceed = 31023;\n\n /// @notice thrown if on liquidation branch debt becomes lower than 100\n uint256 internal constant VaultT1__BranchDebtTooLow = 31024;\n\n /// @notice thrown when tick's debt is less than 10000\n uint256 internal constant VaultT1__TickDebtTooLow = 31025;\n\n /// @notice thrown when the received new liquidity exchange price is of unexpected value (< than the old one)\n uint256 internal constant VaultT1__LiquidityExchangePriceUnexpected = 31026;\n\n /// @notice thrown when user's debt is less than 10000\n uint256 internal constant VaultT1__UserDebtTooLow = 31027;\n\n /// @notice thrown when on only payback and only deposit the ratio of position increases\n uint256 internal constant VaultT1__InvalidPaybackOrDeposit = 31028;\n\n /// @notice thrown when liquidation just happens of a single partial\n uint256 internal constant VaultT1__InvalidLiquidation = 31029;\n\n /// @notice thrown when msg.value is sent wrong in rebalance\n uint256 internal constant VaultT1__InvalidMsgValueInRebalance = 31030;\n\n /// @notice thrown when nothing rebalanced\n uint256 internal constant VaultT1__NothingToRebalance = 31031;\n\n /***********************************|\n | ERC721 | \n |__________________________________*/\n\n uint256 internal constant ERC721__InvalidParams = 32001;\n uint256 internal constant ERC721__Unauthorized = 32002;\n uint256 internal constant ERC721__InvalidOperation = 32003;\n uint256 internal constant ERC721__UnsafeRecipient = 32004;\n uint256 internal constant ERC721__OutOfBoundsIndex = 32005;\n\n /***********************************|\n | Vault Admin | \n |__________________________________*/\n\n /// @notice thrown when admin tries to setup invalid value which are crossing limits\n uint256 internal constant VaultT1Admin__ValueAboveLimit = 33001;\n\n /// @notice when someone directly calls admin implementation contract\n uint256 internal constant VaultT1Admin__OnlyDelegateCallAllowed = 33002;\n\n /// @notice thrown when auth sends NFT ID as 0 while collecting dust debt\n uint256 internal constant VaultT1Admin__NftIdShouldBeNonZero = 33003;\n\n /// @notice thrown when trying to collect dust debt of NFT which is not of this vault\n uint256 internal constant VaultT1Admin__NftNotOfThisVault = 33004;\n\n /// @notice thrown when dust debt of NFT is 0, meaning nothing to collect\n uint256 internal constant VaultT1Admin__DustDebtIsZero = 33005;\n\n /// @notice thrown when final debt after liquidation is not 0, meaning position 100% liquidated\n uint256 internal constant VaultT1Admin__FinalDebtShouldBeZero = 33006;\n\n /// @notice thrown when NFT is not liquidated state\n uint256 internal constant VaultT1Admin__NftNotLiquidated = 33007;\n\n /// @notice thrown when total absorbed dust debt is 0\n uint256 internal constant VaultT1Admin__AbsorbedDustDebtIsZero = 33008;\n\n /// @notice thrown when address is set as 0\n uint256 internal constant VaultT1Admin__AddressZeroNotAllowed = 33009;\n\n /***********************************|\n | Vault Rewards | \n |__________________________________*/\n\n uint256 internal constant VaultRewards__Unauthorized = 34001;\n uint256 internal constant VaultRewards__AddressZero = 34002;\n uint256 internal constant VaultRewards__InvalidParams = 34003;\n uint256 internal constant VaultRewards__NewMagnifierSameAsOldMagnifier = 34004;\n uint256 internal constant VaultRewards__NotTheInitiator = 34005;\n uint256 internal constant VaultRewards__AlreadyStarted = 34006;\n uint256 internal constant VaultRewards__RewardsNotStartedOrEnded = 34007;\n}\n"
},
"contracts/protocols/vault/factory/ERC721/ERC721.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../../errorTypes.sol\";\nimport { Error } from \"../../error.sol\";\n\n/// @notice Fluid Vault Factory ERC721 base contract. Implements the ERC721 standard, based on Solmate.\n/// In addition, implements ERC721 Enumerable.\n/// Modern, minimalist, and gas efficient ERC-721 with Enumerable implementation.\n///\n/// @author Instadapp\n/// @author Modified Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 is Error {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n // token id => token config\n // uint160 0 - 159: address:: owner\n // uint32 160 - 191: uint32:: index\n // uint32 192 - 223: uint32:: vaultId\n // uint32 224 - 255: uint32:: null\n mapping(uint256 => uint256) internal _tokenConfig;\n\n // owner => slot => index\n /*\n // slot 0: \n // uint32 0 - 31: uint32:: balanceOf\n // uint224 32 - 255: 7 tokenIds each of uint32 packed\n // slot N (N >= 1)\n // uint32 * 8 each tokenId\n */\n mapping(address => mapping(uint256 => uint256)) internal _ownerConfig;\n\n /// @notice returns `owner_` of NFT with `id_`\n function ownerOf(uint256 id_) public view virtual returns (address owner_) {\n if ((owner_ = address(uint160(_tokenConfig[id_]))) == address(0))\n revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n }\n\n /// @notice returns total count of NFTs owned by `owner_`\n function balanceOf(address owner_) public view virtual returns (uint256) {\n if (owner_ == address(0)) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n return _ownerConfig[owner_][0] & type(uint32).max;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721Enumerable STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice total amount of tokens stored by the contract.\n uint256 public totalSupply;\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice trackes if a NFT id is approved for a certain address.\n mapping(uint256 => address) public getApproved;\n\n /// @notice trackes if all the NFTs of an owner are approved for a certain other address.\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice approves an NFT with `id_` to be spent (transferred) by `spender_`\n function approve(address spender_, uint256 id_) public virtual {\n address owner_ = address(uint160(_tokenConfig[id_]));\n if (!(msg.sender == owner_ || isApprovedForAll[owner_][msg.sender]))\n revert FluidVaultError(ErrorTypes.ERC721__Unauthorized);\n\n getApproved[id_] = spender_;\n\n emit Approval(owner_, spender_, id_);\n }\n\n /// @notice approves all NFTs owned by msg.sender to be spent (transferred) by `operator_`\n function setApprovalForAll(address operator_, bool approved_) public virtual {\n isApprovedForAll[msg.sender][operator_] = approved_;\n\n emit ApprovalForAll(msg.sender, operator_, approved_);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address without safe check\n function transferFrom(address from_, address to_, uint256 id_) public virtual {\n uint256 tokenConfig_ = _tokenConfig[id_];\n if (from_ != address(uint160(tokenConfig_))) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n if (!(msg.sender == from_ || isApprovedForAll[from_][msg.sender] || msg.sender == getApproved[id_]))\n revert FluidVaultError(ErrorTypes.ERC721__Unauthorized);\n\n // call _transfer with vaultId extracted from tokenConfig_\n _transfer(from_, to_, id_, (tokenConfig_ >> 192) & type(uint32).max);\n\n delete getApproved[id_];\n\n emit Transfer(from_, to_, id_);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address\n function safeTransferFrom(address from_, address to_, uint256 id_) public virtual {\n transferFrom(from_, to_, id_);\n\n if (\n !(to_.code.length == 0 ||\n ERC721TokenReceiver(to_).onERC721Received(msg.sender, from_, id_, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector)\n ) revert FluidVaultError(ErrorTypes.ERC721__UnsafeRecipient);\n }\n\n /// @notice transfers an NFT with `id_` `from_` address `to_` address, passing `data_` to `onERC721Received` callback\n function safeTransferFrom(address from_, address to_, uint256 id_, bytes calldata data_) public virtual {\n transferFrom(from_, to_, id_);\n\n if (\n !((to_.code.length == 0) ||\n ERC721TokenReceiver(to_).onERC721Received(msg.sender, from_, id_, data_) ==\n ERC721TokenReceiver.onERC721Received.selector)\n ) revert FluidVaultError(ErrorTypes.ERC721__UnsafeRecipient);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721Enumerable LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /// @notice 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 function tokenByIndex(uint256 index_) external view returns (uint256) {\n if (index_ >= totalSupply) {\n revert FluidVaultError(ErrorTypes.ERC721__OutOfBoundsIndex);\n }\n return index_ + 1;\n }\n\n /// @notice 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 function tokenOfOwnerByIndex(address owner_, uint256 index_) external view returns (uint256) {\n if (index_ >= balanceOf(owner_)) {\n revert FluidVaultError(ErrorTypes.ERC721__OutOfBoundsIndex);\n }\n\n index_ = index_ + 1;\n return (_ownerConfig[owner_][index_ / 8] >> ((index_ % 8) * 32)) & type(uint32).max;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId_) public view virtual returns (bool) {\n return\n interfaceId_ == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId_ == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId_ == 0x5b5e139f || // ERC165 Interface ID for ERC721Metadata\n interfaceId_ == 0x780e9d63; // ERC165 Interface ID for ERC721Enumberable\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL TRANSFER LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _transfer(address from_, address to_, uint256 id_, uint256 vaultId_) internal {\n if (to_ == address(0)) {\n revert FluidVaultError(ErrorTypes.ERC721__InvalidOperation);\n } else if (from_ == address(0)) {\n _add(to_, id_, vaultId_);\n } else if (to_ != from_) {\n _remove(from_, id_);\n _add(to_, id_, vaultId_);\n }\n }\n\n function _add(address user_, uint256 id_, uint256 vaultId_) private {\n uint256 ownerConfig_ = _ownerConfig[user_][0];\n unchecked {\n // index starts from `1`\n uint256 balanceOf_ = (ownerConfig_ & type(uint32).max) + 1;\n\n _tokenConfig[id_] = (uint160(user_) | (balanceOf_ << 160) | (vaultId_ << 192));\n\n _ownerConfig[user_][0] = (ownerConfig_ & ~uint256(type(uint32).max)) | (balanceOf_);\n\n uint256 wordIndex_ = (balanceOf_ / 8);\n _ownerConfig[user_][wordIndex_] = _ownerConfig[user_][wordIndex_] | (id_ << ((balanceOf_ % 8) * 32));\n }\n }\n\n function _remove(address user_, uint256 id_) private {\n uint256 temp_ = _tokenConfig[id_];\n\n // fetching `id_` details and deleting it.\n uint256 tokenIndex_ = (temp_ >> 160) & type(uint32).max;\n _tokenConfig[id_] = 0;\n\n // fetching & updating balance\n temp_ = _ownerConfig[user_][0];\n uint256 lastTokenIndex_ = (temp_ & type(uint32).max); // (lastTokenIndex_ = balanceOf)\n _ownerConfig[user_][0] = (temp_ & ~uint256(type(uint32).max)) | (lastTokenIndex_ - 1);\n\n {\n unchecked {\n uint256 lastTokenWordIndex_ = (lastTokenIndex_ / 8);\n uint256 lastTokenBitShift_ = (lastTokenIndex_ % 8) * 32;\n temp_ = _ownerConfig[user_][lastTokenWordIndex_];\n\n // replace `id_` tokenId with `last` tokenId.\n if (lastTokenIndex_ != tokenIndex_) {\n uint256 wordIndex_ = (tokenIndex_ / 8);\n uint256 bitShift_ = (tokenIndex_ % 8) * 32;\n\n // temp_ here is _ownerConfig[user_][lastTokenWordIndex_];\n uint256 lastTokenId_ = uint256((temp_ >> lastTokenBitShift_) & type(uint32).max);\n if (wordIndex_ == lastTokenWordIndex_) {\n // this case, when lastToken and currentToken are in same slot.\n // updating temp_ as we will remove the lastToken from this slot itself\n temp_ = (temp_ & ~(uint256(type(uint32).max) << bitShift_)) | (lastTokenId_ << bitShift_);\n } else {\n _ownerConfig[user_][wordIndex_] =\n (_ownerConfig[user_][wordIndex_] & ~(uint256(type(uint32).max) << bitShift_)) |\n (lastTokenId_ << bitShift_);\n }\n _tokenConfig[lastTokenId_] =\n (_tokenConfig[lastTokenId_] & ~(uint256(type(uint32).max) << 160)) |\n (tokenIndex_ << 160);\n }\n\n // temp_ here is _ownerConfig[user_][lastTokenWordIndex_];\n _ownerConfig[user_][lastTokenWordIndex_] = temp_ & ~(uint256(type(uint32).max) << lastTokenBitShift_);\n }\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to_, uint256 vaultId_) internal virtual returns (uint256 id_) {\n\n unchecked {\n ++totalSupply;\n }\n\n id_ = totalSupply;\n if (id_ >= type(uint32).max || _tokenConfig[id_] != 0) revert FluidVaultError(ErrorTypes.ERC721__InvalidParams);\n\n _transfer(address(0), to_, id_, vaultId_);\n\n emit Transfer(address(0), to_, id_);\n }\n}\n\nabstract contract ERC721TokenReceiver {\n function onERC721Received(address, address, uint256, bytes calldata) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/protocols/vault/factory/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Owned } from \"solmate/src/auth/Owned.sol\";\nimport { ERC721 } from \"./ERC721/ERC721.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\nimport { StorageRead } from \"../../../libraries/storageRead.sol\";\n\nabstract contract VaultFactoryVariables is Owned, ERC721, StorageRead {\n /// @dev ERC721 tokens name\n string internal constant ERC721_NAME = \"Fluid Vault\";\n /// @dev ERC721 tokens symbol\n string internal constant ERC721_SYMBOL = \"fVLT\";\n\n /*//////////////////////////////////////////////////////////////\n STORAGE VARIABLES\n //////////////////////////////////////////////////////////////*/\n\n // ------------ storage variables from inherited contracts (Owned and ERC721) come before vars here --------\n\n // ----------------------- slot 0 ---------------------------\n // address public owner; // from Owned\n\n // 12 bytes empty\n\n // ----------------------- slot 1 ---------------------------\n // string public name;\n\n // ----------------------- slot 2 ---------------------------\n // string public symbol;\n\n // ----------------------- slot 3 ---------------------------\n // mapping(uint256 => uint256) internal _tokenConfig;\n\n // ----------------------- slot 4 ---------------------------\n // mapping(address => mapping(uint256 => uint256)) internal _ownerConfig;\n\n // ----------------------- slot 5 ---------------------------\n // uint256 public totalSupply;\n\n // ----------------------- slot 6 ---------------------------\n // mapping(uint256 => address) public getApproved;\n\n // ----------------------- slot 7 ---------------------------\n // mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n // ----------------------- slot 8 ---------------------------\n /// @dev deployer can deploy new Vault contract\n /// owner can add/remove deployer.\n /// Owner is deployer by default.\n mapping(address => bool) internal _deployers;\n\n // ----------------------- slot 9 ---------------------------\n /// @dev global auths can update any vault config.\n /// owner can add/remove global auths.\n /// Owner is global auth by default.\n mapping(address => bool) internal _globalAuths;\n\n // ----------------------- slot 10 ---------------------------\n /// @dev vault auths can update specific vault config.\n /// owner can add/remove vault auths.\n /// Owner is vault auth by default.\n /// vault => auth => add/remove\n mapping(address => mapping(address => bool)) internal _vaultAuths;\n\n // ----------------------- slot 11 ---------------------------\n /// @dev total no of vaults deployed by the factory\n /// only addresses that have deployer role or owner can deploy new vault.\n uint256 internal _totalVaults;\n\n // ----------------------- slot 12 ---------------------------\n /// @dev vault deployment logics for deploying vault\n /// These logic contracts hold the deployment logics of specific vaults and are called via .delegatecall inside deployVault().\n /// only addresses that have owner can add/remove new vault deployment logic.\n mapping(address => bool) internal _vaultDeploymentLogics;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n constructor(address owner_) Owned(owner_) ERC721(ERC721_NAME, ERC721_SYMBOL) {}\n}\n\nabstract contract VaultFactoryEvents {\n /// @dev Emitted when a new vault is deployed.\n /// @param vault The address of the newly deployed vault.\n /// @param vaultId The id of the newly deployed vault.\n event VaultDeployed(address indexed vault, uint256 indexed vaultId);\n\n /// @dev Emitted when a new token/position is minted by a vault.\n /// @param vault The address of the vault that minted the token.\n /// @param user The address of the user who received the minted token.\n /// @param tokenId The ID of the newly minted token.\n event NewPositionMinted(address indexed vault, address indexed user, uint256 indexed tokenId);\n\n /// @dev Emitted when the deployer is modified by owner.\n /// @param deployer Address whose deployer status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetDeployer(address indexed deployer, bool indexed allowed);\n\n /// @dev Emitted when the globalAuth is modified by owner.\n /// @param globalAuth Address whose globalAuth status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetGlobalAuth(address indexed globalAuth, bool indexed allowed);\n\n /// @dev Emitted when the vaultAuth is modified by owner.\n /// @param vaultAuth Address whose vaultAuth status is updated.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n /// @param vault Address of the specific vault related to the authorization change.\n event LogSetVaultAuth(address indexed vaultAuth, bool indexed allowed, address indexed vault);\n\n /// @dev Emitted when the vault deployment logic is modified by owner.\n /// @param vaultDeploymentLogic The address of the vault deployment logic contract.\n /// @param allowed Indicates whether the address is authorized as a deployer or not.\n event LogSetVaultDeploymentLogic(address indexed vaultDeploymentLogic, bool indexed allowed);\n}\n\nabstract contract VaultFactoryCore is VaultFactoryVariables, VaultFactoryEvents {\n constructor(address owner_) validAddress(owner_) VaultFactoryVariables(owner_) {}\n\n /// @dev validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidParams);\n }\n _;\n }\n}\n\n/// @dev Implements Vault Factory auth-only callable methods. Owner / auths can set various config values and\n/// can define the allow-listed deployers.\nabstract contract VaultFactoryAuth is VaultFactoryCore {\n /// @notice Sets an address (`deployer_`) as allowed deployer or not.\n /// This function can only be called by the owner.\n /// @param deployer_ The address to be set as deployer.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to deploy vaults.\n function setDeployer(address deployer_, bool allowed_) external onlyOwner validAddress(deployer_) {\n _deployers[deployer_] = allowed_;\n\n emit LogSetDeployer(deployer_, allowed_);\n }\n\n /// @notice Sets an address (`globalAuth_`) as a global authorization or not.\n /// This function can only be called by the owner.\n /// @param globalAuth_ The address to be set as global authorization.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to update any vault config.\n function setGlobalAuth(address globalAuth_, bool allowed_) external onlyOwner validAddress(globalAuth_) {\n _globalAuths[globalAuth_] = allowed_;\n\n emit LogSetGlobalAuth(globalAuth_, allowed_);\n }\n\n /// @notice Sets an address (`vaultAuth_`) as allowed vault authorization or not for a specific vault (`vault_`).\n /// This function can only be called by the owner.\n /// @param vault_ The address of the vault for which the authorization is being set.\n /// @param vaultAuth_ The address to be set as vault authorization.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to update the specific vault config.\n function setVaultAuth(\n address vault_,\n address vaultAuth_,\n bool allowed_\n ) external onlyOwner validAddress(vaultAuth_) {\n _vaultAuths[vault_][vaultAuth_] = allowed_;\n\n emit LogSetVaultAuth(vaultAuth_, allowed_, vault_);\n }\n\n /// @notice Sets an address as allowed vault deployment logic (`deploymentLogic_`) contract or not.\n /// This function can only be called by the owner.\n /// @param deploymentLogic_ The address of the vault deployment logic contract to be set.\n /// @param allowed_ A boolean indicating whether the specified address is allowed to deploy new type of vault.\n function setVaultDeploymentLogic(\n address deploymentLogic_,\n bool allowed_\n ) public onlyOwner validAddress(deploymentLogic_) {\n _vaultDeploymentLogics[deploymentLogic_] = allowed_;\n\n emit LogSetVaultDeploymentLogic(deploymentLogic_, allowed_);\n }\n\n /// @notice Spell allows owner aka governance to do any arbitrary call on factory\n /// @param target_ Address to which the call needs to be delegated\n /// @param data_ Data to execute at the delegated address\n function spell(address target_, bytes memory data_) external onlyOwner returns (bytes memory response_) {\n assembly {\n let succeeded := delegatecall(gas(), target_, add(data_, 0x20), mload(data_), 0, 0)\n let size := returndatasize()\n\n response_ := mload(0x40)\n mstore(0x40, add(response_, and(add(add(size, 0x20), 0x1f), not(0x1f))))\n mstore(response_, size)\n returndatacopy(add(response_, 0x20), 0, size)\n\n switch iszero(succeeded)\n case 1 {\n // throw if delegatecall failed\n returndatacopy(0x00, 0x00, size)\n revert(0x00, size)\n }\n }\n }\n\n /// @notice Checks if the provided address (`deployer_`) is authorized as a deployer.\n /// @param deployer_ The address to be checked for deployer authorization.\n /// @return Returns `true` if the address is a deployer, otherwise `false`.\n function isDeployer(address deployer_) public view returns (bool) {\n return _deployers[deployer_] || owner == deployer_;\n }\n\n /// @notice Checks if the provided address (`globalAuth_`) has global vault authorization privileges.\n /// @param globalAuth_ The address to be checked for global authorization privileges.\n /// @return Returns `true` if the given address has global authorization privileges, otherwise `false`.\n function isGlobalAuth(address globalAuth_) public view returns (bool) {\n return _globalAuths[globalAuth_] || owner == globalAuth_;\n }\n\n /// @notice Checks if the provided address (`vaultAuth_`) has vault authorization privileges for the specified vault (`vault_`).\n /// @param vault_ The address of the vault to check.\n /// @param vaultAuth_ The address to be checked for vault authorization privileges.\n /// @return Returns `true` if the given address has vault authorization privileges for the specified vault, otherwise `false`.\n function isVaultAuth(address vault_, address vaultAuth_) public view returns (bool) {\n return _vaultAuths[vault_][vaultAuth_] || owner == vaultAuth_;\n }\n\n /// @notice Checks if the provided (`vaultDeploymentLogic_`) address has authorization for vault deployment.\n /// @param vaultDeploymentLogic_ The address of the vault deploy logic to check for authorization privileges.\n /// @return Returns `true` if the given address has authorization privileges for vault deployment, otherwise `false`.\n function isVaultDeploymentLogic(address vaultDeploymentLogic_) public view returns (bool) {\n return _vaultDeploymentLogics[vaultDeploymentLogic_];\n }\n}\n\n/// @dev implements VaultFactory deploy vault related methods.\nabstract contract VaultFactoryDeployment is VaultFactoryCore, VaultFactoryAuth {\n /// @dev Deploys a contract using the CREATE opcode with the provided bytecode (`bytecode_`).\n /// This is an internal function, meant to be used within the contract to facilitate the deployment of other contracts.\n /// @param bytecode_ The bytecode of the contract to be deployed.\n /// @return address_ Returns the address of the deployed contract.\n function _deploy(bytes memory bytecode_) internal returns (address address_) {\n if (bytecode_.length == 0) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidOperation);\n }\n /// @solidity memory-safe-assembly\n assembly {\n address_ := create(0, add(bytecode_, 0x20), mload(bytecode_))\n }\n if (address_ == address(0)) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidOperation);\n }\n }\n\n /// @notice Deploys a new vault using the specified deployment logic `vaultDeploymentLogic_` and data `vaultDeploymentData_`.\n /// Only accounts with deployer access or the owner can deploy a new vault.\n /// @param vaultDeploymentLogic_ The address of the vault deployment logic contract.\n /// @param vaultDeploymentData_ The data to be used for vault deployment.\n /// @return vault_ Returns the address of the newly deployed vault.\n function deployVault(\n address vaultDeploymentLogic_,\n bytes calldata vaultDeploymentData_\n ) external returns (address vault_) {\n // Revert if msg.sender doesn't have deployer access or is an owner.\n if (!isDeployer(msg.sender)) revert FluidVaultError(ErrorTypes.VaultFactory__Unauthorized);\n // Revert if vaultDeploymentLogic_ is not whitelisted.\n if (!isVaultDeploymentLogic(vaultDeploymentLogic_))\n revert FluidVaultError(ErrorTypes.VaultFactory__Unauthorized);\n\n // Vault ID for the new vault and also acts as `nonce` for CREATE\n uint256 vaultId_ = ++_totalVaults;\n\n // compute vault address for vault id.\n vault_ = getVaultAddress(vaultId_);\n\n // deploy the vault using vault deployment logic by making .delegatecall\n (bool success_, bytes memory data_) = vaultDeploymentLogic_.delegatecall(vaultDeploymentData_);\n\n if (!(success_ && vault_ == _deploy(abi.decode(data_, (bytes))) && isVault(vault_))) {\n revert FluidVaultError(ErrorTypes.VaultFactory__InvalidVaultAddress);\n }\n\n emit VaultDeployed(vault_, vaultId_);\n }\n\n /// @notice Computes the address of a vault based on its given ID (`vaultId_`).\n /// @param vaultId_ The ID of the vault.\n /// @return vault_ Returns the computed address of the vault.\n function getVaultAddress(uint256 vaultId_) public view returns (address vault_) {\n // @dev based on https://ethereum.stackexchange.com/a/61413\n\n // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment\n // hence, nonce of vault deployment starts with 1.\n bytes memory data;\n if (vaultId_ == 0x00) {\n return address(0);\n } else if (vaultId_ <= 0x7f) {\n data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), address(this), uint8(vaultId_));\n } else if (vaultId_ <= 0xff) {\n data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), address(this), bytes1(0x81), uint8(vaultId_));\n } else if (vaultId_ <= 0xffff) {\n data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), address(this), bytes1(0x82), uint16(vaultId_));\n } else if (vaultId_ <= 0xffffff) {\n data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), address(this), bytes1(0x83), uint24(vaultId_));\n } else {\n data = abi.encodePacked(bytes1(0xda), bytes1(0x94), address(this), bytes1(0x84), uint32(vaultId_));\n }\n\n return address(uint160(uint256(keccak256(data))));\n }\n\n /// @notice Checks if a given address (`vault_`) corresponds to a valid vault.\n /// @param vault_ The vault address to check.\n /// @return Returns `true` if the given address corresponds to a valid vault, otherwise `false`.\n function isVault(address vault_) public view returns (bool) {\n if (vault_.code.length == 0) {\n return false;\n } else {\n // VAULT_ID() function signature is 0x540acabc\n (bool success_, bytes memory data_) = vault_.staticcall(hex\"540acabc\");\n return success_ && vault_ == getVaultAddress(abi.decode(data_, (uint256)));\n }\n }\n\n /// @notice Returns the total number of vaults deployed by the factory.\n /// @return Returns the total number of vaults.\n function totalVaults() external view returns (uint256) {\n return _totalVaults;\n }\n}\n\nabstract contract VaultFactoryERC721 is VaultFactoryCore, VaultFactoryDeployment {\n /// @notice Mints a new ERC721 token for a specific vault (`vaultId_`) to a specified user (`user_`).\n /// Only the corresponding vault is authorized to mint a token.\n /// @param vaultId_ The ID of the vault that's minting the token.\n /// @param user_ The address receiving the minted token.\n /// @return tokenId_ The ID of the newly minted token.\n function mint(uint256 vaultId_, address user_) external returns (uint256 tokenId_) {\n if (msg.sender != getVaultAddress(vaultId_)) revert FluidVaultError(ErrorTypes.VaultFactory__InvalidVault);\n\n // Using _mint() instead of _safeMint() to allow any msg.sender to receive ERC721 without onERC721Received holder.\n tokenId_ = _mint(user_, vaultId_);\n\n emit NewPositionMinted(msg.sender, user_, tokenId_);\n }\n\n /// @notice Returns the URI of the specified token ID (`id_`).\n /// In this implementation, an empty string is returned as no specific URI is defined.\n /// @param id_ The ID of the token to query.\n /// @return An empty string since no specific URI is defined in this implementation.\n function tokenURI(uint256 id_) public view virtual override returns (string memory) {\n return \"\";\n }\n}\n\n/// @title Fluid VaultFactory\n/// @notice creates Fluid vault protocol vaults, which are interacting with Fluid Liquidity to deposit / borrow funds.\n/// Vaults are created at a deterministic address, given an incrementing `vaultId` (see `getVaultAddress()`).\n/// Vaults can only be deployed by allow-listed deployer addresses.\n/// This factory also implements ERC721-Enumerable, the NFTs are used to represent created user positions. Only vaults\n/// can mint new NFTs.\n/// @dev Note the deployed vaults start out with no config at Liquidity contract.\n/// This must be done by Liquidity auths in a separate step, otherwise no deposits will be possible.\n/// This contract is not upgradeable. It supports adding new vault deployment logic contracts for new, future vaults.\ncontract FluidVaultFactory is VaultFactoryCore, VaultFactoryAuth, VaultFactoryDeployment, VaultFactoryERC721 {\n constructor(address owner_) VaultFactoryCore(owner_) {}\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"
},
"contracts/protocols/vault/rewards/events.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Events {\n /// @notice Emitted when magnifier is updated\n event LogUpdateMagnifier(address indexed vault, uint256 newMagnifier);\n\n /// @notice Emitted when rewards are started\n event LogRewardsStarted(uint256 startTime, uint256 endTime);\n}\n"
},
"contracts/protocols/vault/rewards/main.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { FluidVaultT1Admin } from \"../vaultT1/adminModule/main.sol\";\nimport { IFluidVaultT1 } from \"../interfaces/iVaultT1.sol\";\nimport { IFluidReserveContract } from \"../../../reserve/interfaces/iReserveContract.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { Events } from \"./events.sol\";\nimport { Variables } from \"./variables.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error } from \"../error.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\n\n/// @title VaultRewards\n/// @notice This contract is designed to adjust the supply rate magnifier for a vault based on the current collateral supply & supply rate.\n/// The adjustment aims to dynamically scale the rewards given to lenders as the TVL in the vault changes.\n///\n/// The magnifier is adjusted based on a regular most used reward type where rewardRate = totalRewardsAnnually / totalSupply.\n/// Reward rate is applied by adjusting the supply magnifier on vault.\n/// Adjustments are made via the rebalance function, which is restricted to be called by designated rebalancers only.\ncontract FluidVaultRewards is Variables, Events, Error {\n /// @dev Validates that an address is not the zero address\n modifier validAddress(address value_) {\n if (value_ == address(0)) {\n revert FluidVaultError(ErrorTypes.VaultRewards__AddressZero);\n }\n _;\n }\n\n /// @dev Validates that an address is a rebalancer (taken from reserve contract)\n modifier onlyRebalancer() {\n if (!RESERVE_CONTRACT.isRebalancer(msg.sender)) {\n revert FluidVaultError(ErrorTypes.VaultRewards__Unauthorized);\n }\n _;\n }\n\n /// @notice Constructs the FluidVaultRewards contract.\n /// @param reserveContract_ The address of the reserve contract where rebalancers are defined.\n /// @param vault_ The vault to which this contract will apply new magnifier parameter.\n /// @param liquidity_ Fluid liquidity address\n /// @param rewardsAmt_ Amounts of rewards to distribute\n /// @param duration_ rewards duration\n /// @param initiator_ address that can start rewards with `start()`\n /// @param collateralToken_ vault collateral token address\n constructor(\n IFluidReserveContract reserveContract_,\n IFluidVaultT1 vault_,\n IFluidLiquidity liquidity_,\n uint256 rewardsAmt_,\n uint256 duration_,\n address initiator_,\n address collateralToken_\n ) validAddress(address(reserveContract_)) validAddress(address(liquidity_)) validAddress(address(vault_)) validAddress(initiator_) validAddress(address(collateralToken_)){\n if (rewardsAmt_ == 0 || duration_ == 0) {\n revert FluidVaultError(ErrorTypes.VaultRewards__InvalidParams);\n }\n RESERVE_CONTRACT = reserveContract_;\n VAULT = vault_;\n REWARDS_AMOUNT = rewardsAmt_;\n REWARDS_AMOUNT_PER_YEAR = rewardsAmt_ * SECONDS_PER_YEAR / duration_;\n DURATION = duration_;\n INITIATOR = initiator_;\n LIQUIDITY = liquidity_;\n VAULT_COLLATERAL_TOKEN = collateralToken_;\n\n LIQUIDITY_TOTAL_AMOUNTS_COLLATERAL_TOKEN_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT,\n collateralToken_\n );\n LIQUIDITY_EXCHANGE_PRICE_COLLATERAL_TOKEN_SLOT = LiquiditySlotsLink.calculateMappingStorageSlot(\n LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT,\n collateralToken_\n );\n }\n\n /// @notice Rebalances the supply rate magnifier based on the current collateral supply.\n /// Can only be called by an authorized rebalancer.\n function rebalance() external onlyRebalancer {\n (uint256 newMagnifier_, bool ended_) = calculateMagnifier();\n if (ended_) {\n ended = true;\n }\n if (newMagnifier_ == currentMagnifier()) {\n revert FluidVaultError(ErrorTypes.VaultRewards__NewMagnifierSameAsOldMagnifier);\n }\n\n FluidVaultT1Admin(address(VAULT)).updateSupplyRateMagnifier(newMagnifier_);\n emit LogUpdateMagnifier(address(VAULT), newMagnifier_);\n }\n\n /// @notice Calculates the new supply rate magnifier based on the current collateral supply (`vaultTVL()`).\n /// @return magnifier_ The calculated magnifier value.\n function calculateMagnifier() public view returns (uint256 magnifier_, bool ended_) {\n uint256 currentTVL_ = vaultTVL();\n uint256 startTime_ = uint256(startTime);\n uint256 endTime_ = uint256(endTime);\n\n if (startTime_ == 0 || endTime_ == 0 || ended) {\n revert FluidVaultError(ErrorTypes.VaultRewards__RewardsNotStartedOrEnded);\n }\n\n if (block.timestamp > endTime_) {\n return (FOUR_DECIMALS, true);\n }\n\n uint supplyRate_ = getSupplyRate();\n uint rewardsRate_ = (REWARDS_AMOUNT_PER_YEAR * FOUR_DECIMALS) / currentTVL_;\n\n magnifier_ = FOUR_DECIMALS + (supplyRate_ == 0 ? rewardsRate_ : ((rewardsRate_ * FOUR_DECIMALS) / supplyRate_));\n if (magnifier_ > X16) {\n magnifier_ = X16;\n }\n }\n\n /// @notice returns the currently configured supply magnifier at the `VAULT`.\n function currentMagnifier() public view returns (uint256) {\n // read supply rate magnifier from Vault `vaultVariables2` located in storage slot 1, first 16 bits\n return VAULT.readFromStorage(bytes32(uint256(1))) & X16;\n }\n\n /// @notice returns the current total value locked as collateral (TVL) in the `VAULT`.\n function vaultTVL() public view returns (uint256 tvl_) {\n // read total supply raw in vault from storage slot 0 `vaultVariables`, 64 bits 82-145\n tvl_ = (VAULT.readFromStorage(bytes32(0)) >> 82) & 0xFFFFFFFFFFFFFFFF;\n\n // Converting bignumber into normal number\n tvl_ = (tvl_ >> 8) << (tvl_ & 0xFF);\n\n // get updated supply exchange price, which takes slot 1 `vaultVariables2` as input param\n (, , uint256 vaultSupplyExPrice_, ) = VAULT.updateExchangePrices(VAULT.readFromStorage(bytes32(uint256(1))));\n\n // converting raw total supply into normal amount\n tvl_ = (tvl_ * vaultSupplyExPrice_) / 1e12;\n }\n\n function getSupplyRate() public view returns (uint supplyRate_) {\n uint256 exchangePriceAndConfig_ = LIQUIDITY.readFromStorage(LIQUIDITY_EXCHANGE_PRICE_COLLATERAL_TOKEN_SLOT);\n uint256 totalAmounts_ = LIQUIDITY.readFromStorage(LIQUIDITY_TOTAL_AMOUNTS_COLLATERAL_TOKEN_SLOT);\n\n uint borrowRate_ = exchangePriceAndConfig_ & X16;\n uint fee_ = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14;\n uint supplyExchangePrice_ = ((exchangePriceAndConfig_ >>\n LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) & X64);\n uint borrowExchangePrice_ = ((exchangePriceAndConfig_ >>\n LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) & X64);\n\n // Extract supply raw interest\n uint256 supplyWithInterest_ = totalAmounts_ & X64;\n supplyWithInterest_ =\n (supplyWithInterest_ >> DEFAULT_EXPONENT_SIZE) <<\n (supplyWithInterest_ & DEFAULT_EXPONENT_MASK);\n\n // Extract borrow raw interest\n uint256 borrowWithInterest_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) &\n X64;\n borrowWithInterest_ =\n (borrowWithInterest_ >> DEFAULT_EXPONENT_SIZE) <<\n (borrowWithInterest_ & DEFAULT_EXPONENT_MASK);\n\n if (supplyWithInterest_ > 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_ = (supplyWithInterest_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION; // normalized from raw\n borrowWithInterest_ = (borrowWithInterest_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION; // normalized from raw\n\n supplyRate_ =\n (borrowRate_ * (FOUR_DECIMALS - fee_) * borrowWithInterest_) /\n (supplyWithInterest_ * FOUR_DECIMALS);\n }\n }\n\n function start() external {\n if (msg.sender != INITIATOR) {\n revert FluidVaultError(ErrorTypes.VaultRewards__NotTheInitiator);\n }\n if (startTime > 0 || endTime > 0) {\n revert FluidVaultError(ErrorTypes.VaultRewards__AlreadyStarted);\n }\n startTime = uint96(block.timestamp);\n endTime = uint96(block.timestamp + DURATION);\n\n emit LogRewardsStarted(startTime, endTime);\n }\n}\n"
},
"contracts/protocols/vault/rewards/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidReserveContract } from \"../../../reserve/interfaces/iReserveContract.sol\";\nimport { IFluidVaultT1 } from \"../interfaces/iVaultT1.sol\";\nimport { IFluidLiquidity } from \"../../../liquidity/interfaces/iLiquidity.sol\";\n\nabstract contract Constants {\n IFluidLiquidity public immutable LIQUIDITY;\n IFluidReserveContract public immutable RESERVE_CONTRACT;\n IFluidVaultT1 public immutable VAULT;\n uint256 public immutable REWARDS_AMOUNT;\n uint256 public immutable REWARDS_AMOUNT_PER_YEAR;\n uint256 public immutable DURATION;\n address public immutable INITIATOR;\n address public immutable VAULT_COLLATERAL_TOKEN;\n\n bytes32 internal immutable LIQUIDITY_TOTAL_AMOUNTS_COLLATERAL_TOKEN_SLOT;\n bytes32 internal immutable LIQUIDITY_EXCHANGE_PRICE_COLLATERAL_TOKEN_SLOT;\n uint256 internal constant FOUR_DECIMALS = 10000;\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n uint256 internal constant DEFAULT_EXPONENT_MASK = 0xff;\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n uint256 internal constant X14 = 0x3fff;\n uint256 internal constant X16 = 0xffff;\n uint256 internal constant X64 = 0xffffffffffffffff;\n}\n\nabstract contract Variables is Constants {\n bool public ended; // when rewards are ended\n uint96 public startTime;\n uint96 public endTime;\n}\n"
},
"contracts/protocols/vault/vaultT1/adminModule/events.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Events {\n /// @notice emitted when the supply rate magnifier config is updated\n event LogUpdateSupplyRateMagnifier(uint supplyRateMagnifier_);\n\n /// @notice emitted when the borrow rate magnifier config is updated\n event LogUpdateBorrowRateMagnifier(uint borrowRateMagnifier_);\n\n /// @notice emitted when the collateral factor config is updated\n event LogUpdateCollateralFactor(uint collateralFactor_);\n\n /// @notice emitted when the liquidation threshold config is updated\n event LogUpdateLiquidationThreshold(uint liquidationThreshold_);\n\n /// @notice emitted when the liquidation max limit config is updated\n event LogUpdateLiquidationMaxLimit(uint liquidationMaxLimit_);\n\n /// @notice emitted when the withdrawal gap config is updated\n event LogUpdateWithdrawGap(uint withdrawGap_);\n\n /// @notice emitted when the liquidation penalty config is updated\n event LogUpdateLiquidationPenalty(uint liquidationPenalty_);\n\n /// @notice emitted when the borrow fee config is updated\n event LogUpdateBorrowFee(uint borrowFee_);\n\n /// @notice emitted when the core setting configs are updated\n event LogUpdateCoreSettings(\n uint supplyRateMagnifier_,\n uint borrowRateMagnifier_,\n uint collateralFactor_,\n uint liquidationThreshold_,\n uint liquidationMaxLimit_,\n uint withdrawGap_,\n uint liquidationPenalty_,\n uint borrowFee_\n );\n\n /// @notice emitted when the oracle is updated\n event LogUpdateOracle(address indexed newOracle_);\n\n /// @notice emitted when the allowed rebalancer is updated\n event LogUpdateRebalancer(address indexed newRebalancer_);\n\n /// @notice emitted when funds are rescued\n event LogRescueFunds(address indexed token_);\n\n /// @notice emitted when dust debt is absorbed for `nftIds_`\n event LogAbsorbDustDebt(uint256[] nftIds_, uint256 absorbedDustDebt_);\n}\n"
},
"contracts/protocols/vault/vaultT1/adminModule/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\";\nimport { Events } from \"./events.sol\";\nimport { ErrorTypes } from \"../../errorTypes.sol\";\nimport { Error } from \"../../error.sol\";\nimport { IFluidVaultT1 } from \"../../interfaces/iVaultT1.sol\";\nimport { BigMathMinified } from \"../../../../libraries/bigMathMinified.sol\";\nimport { TickMath } from \"../../../../libraries/tickMath.sol\";\n\n/// @notice Fluid Vault protocol Admin Module contract.\n/// Implements admin related methods to set configs such as liquidation params, rates\n/// oracle address etc.\n/// Methods are limited to be called via delegateCall only. Vault CoreModule (\"VaultT1\" contract)\n/// is expected to call the methods implemented here after checking the msg.sender is authorized.\n/// All methods update the exchange prices in storage before changing configs.\ncontract FluidVaultT1Admin is Variables, Events, Error {\n uint private constant X8 = 0xff;\n uint private constant X10 = 0x3ff;\n uint private constant X16 = 0xffff;\n uint private constant X19 = 0x7ffff;\n uint private constant X24 = 0xffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n uint private constant X96 = 0xffffffffffffffffffffffff;\n address private constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n address private immutable addressThis;\n\n constructor() {\n addressThis = address(this);\n }\n\n modifier _verifyCaller() {\n if (address(this) == addressThis) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__OnlyDelegateCallAllowed);\n }\n _;\n }\n\n /// @dev updates exchange price on storage, called on all admin methods in combination with _verifyCaller modifier so\n /// only called by authorized delegatecall\n modifier _updateExchangePrice() {\n IFluidVaultT1(address(this)).updateExchangePricesOnStorage();\n _;\n }\n\n function _checkLiquidationMaxLimitAndPenalty(uint liquidationMaxLimit_, uint liquidationPenalty_) private pure {\n // liquidation max limit with penalty should not go above 99.7%\n // As liquidation with penalty can happen from liquidation Threshold to max limit\n // If it goes above 100% than that means liquidator is getting more collateral than user's available\n if ((liquidationMaxLimit_ + liquidationPenalty_) > 9970) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n }\n }\n\n /// @notice updates the supply rate magnifier to `supplyRateMagnifier_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateSupplyRateMagnifier(uint supplyRateMagnifier_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateSupplyRateMagnifier(supplyRateMagnifier_);\n\n if (supplyRateMagnifier_ > X16) revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000) |\n supplyRateMagnifier_;\n }\n\n /// @notice updates the borrow rate magnifier to `borrowRateMagnifier_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateBorrowRateMagnifier(uint borrowRateMagnifier_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateBorrowRateMagnifier(borrowRateMagnifier_);\n\n if (borrowRateMagnifier_ > X16) revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff) |\n (borrowRateMagnifier_ << 16);\n }\n\n /// @notice updates the collateral factor to `collateralFactor_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateCollateralFactor(uint collateralFactor_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateCollateralFactor(collateralFactor_);\n\n uint vaultVariables2_ = vaultVariables2;\n uint liquidationThreshold_ = ((vaultVariables2_ >> 42) & X10);\n\n collateralFactor_ = collateralFactor_ / 10;\n\n if (collateralFactor_ >= liquidationThreshold_)\n revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffc00ffffffff) |\n (collateralFactor_ << 32);\n }\n\n /// @notice updates the liquidation threshold to `liquidationThreshold_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateLiquidationThreshold(uint liquidationThreshold_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateLiquidationThreshold(liquidationThreshold_);\n\n uint vaultVariables2_ = vaultVariables2;\n uint collateralFactor_ = ((vaultVariables2_ >> 32) & X10);\n uint liquidationMaxLimit_ = ((vaultVariables2_ >> 52) & X10);\n\n liquidationThreshold_ = liquidationThreshold_ / 10;\n\n if ((collateralFactor_ >= liquidationThreshold_) || (liquidationThreshold_ >= liquidationMaxLimit_))\n revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffffffffff003ffffffffff) |\n (liquidationThreshold_ << 42);\n }\n\n /// @notice updates the liquidation max limit to `liquidationMaxLimit_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateLiquidationMaxLimit(uint liquidationMaxLimit_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateLiquidationMaxLimit(liquidationMaxLimit_);\n\n uint vaultVariables2_ = vaultVariables2;\n uint liquidationThreshold_ = ((vaultVariables2_ >> 42) & X10);\n uint liquidationPenalty_ = ((vaultVariables2_ >> 72) & X10);\n\n // both are in 1e2 decimals (1e2 = 1%)\n _checkLiquidationMaxLimitAndPenalty(liquidationMaxLimit_, liquidationPenalty_);\n\n liquidationMaxLimit_ = liquidationMaxLimit_ / 10;\n\n if (liquidationThreshold_ >= liquidationMaxLimit_)\n revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2_ & 0xffffffffffffffffffffffffffffffffffffffffffffffffc00fffffffffffff) |\n (liquidationMaxLimit_ << 52);\n }\n\n /// @notice updates the withdrawal gap to `withdrawGap_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateWithdrawGap(uint withdrawGap_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateWithdrawGap(withdrawGap_);\n\n withdrawGap_ = withdrawGap_ / 10;\n\n // withdrawGap must not be > 100%\n if (withdrawGap_ > 1000) revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2 & 0xffffffffffffffffffffffffffffffffffffffffffffff003fffffffffffffff) |\n (withdrawGap_ << 62);\n }\n\n /// @notice updates the liquidation penalty to `liquidationPenalty_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateLiquidationPenalty(uint liquidationPenalty_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateLiquidationPenalty(liquidationPenalty_);\n\n uint vaultVariables2_ = vaultVariables2;\n uint liquidationMaxLimit_ = ((vaultVariables2_ >> 52) & X10);\n\n // Converting liquidationMaxLimit_ in 1e2 decimals (1e2 = 1%)\n _checkLiquidationMaxLimitAndPenalty((liquidationMaxLimit_ * 10), liquidationPenalty_);\n\n if (liquidationPenalty_ > X10) revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2_ & 0xfffffffffffffffffffffffffffffffffffffffffffc00ffffffffffffffffff) |\n (liquidationPenalty_ << 72);\n }\n\n /// @notice updates the borrow fee to `borrowFee_`. Input in 1e2 (1% = 100, 100% = 10_000).\n function updateBorrowFee(uint borrowFee_) public _updateExchangePrice _verifyCaller {\n emit LogUpdateBorrowFee(borrowFee_);\n\n if (borrowFee_ > X10) revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n\n vaultVariables2 =\n (vaultVariables2 & 0xfffffffffffffffffffffffffffffffffffffffff003ffffffffffffffffffff) |\n (borrowFee_ << 82);\n }\n\n /// @notice updates the all Vault core settings according to input params.\n /// All input values are expected in 1e2 (1% = 100, 100% = 10_000).\n function updateCoreSettings(\n uint256 supplyRateMagnifier_,\n uint256 borrowRateMagnifier_,\n uint256 collateralFactor_,\n uint256 liquidationThreshold_,\n uint256 liquidationMaxLimit_,\n uint256 withdrawGap_,\n uint256 liquidationPenalty_,\n uint256 borrowFee_\n ) public _updateExchangePrice _verifyCaller {\n // emitting the event at the start as then we are updating numbers to store in a more optimized way\n emit LogUpdateCoreSettings(\n supplyRateMagnifier_,\n borrowRateMagnifier_,\n collateralFactor_,\n liquidationThreshold_,\n liquidationMaxLimit_,\n withdrawGap_,\n liquidationPenalty_,\n borrowFee_\n );\n\n _checkLiquidationMaxLimitAndPenalty(liquidationMaxLimit_, liquidationPenalty_);\n\n collateralFactor_ = collateralFactor_ / 10;\n liquidationThreshold_ = liquidationThreshold_ / 10;\n liquidationMaxLimit_ = liquidationMaxLimit_ / 10;\n withdrawGap_ = withdrawGap_ / 10;\n\n if (\n (supplyRateMagnifier_ > X16) ||\n (borrowRateMagnifier_ > X16) ||\n (collateralFactor_ >= liquidationThreshold_) ||\n (liquidationThreshold_ >= liquidationMaxLimit_) ||\n (withdrawGap_ > X10) ||\n (liquidationPenalty_ > X10) ||\n (borrowFee_ > X10)\n ) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__ValueAboveLimit);\n }\n\n vaultVariables2 =\n (vaultVariables2 & 0xfffffffffffffffffffffffffffffffffffffffff00000000000000000000000) |\n supplyRateMagnifier_ |\n (borrowRateMagnifier_ << 16) |\n (collateralFactor_ << 32) |\n (liquidationThreshold_ << 42) |\n (liquidationMaxLimit_ << 52) |\n (withdrawGap_ << 62) |\n (liquidationPenalty_ << 72) |\n (borrowFee_ << 82);\n }\n\n /// @notice updates the Vault oracle to `newOracle_`. Must implement the FluidOracle interface.\n function updateOracle(address newOracle_) public _updateExchangePrice _verifyCaller {\n if (newOracle_ == address(0)) revert FluidVaultError(ErrorTypes.VaultT1Admin__AddressZeroNotAllowed);\n\n // Removing current oracle by masking only first 96 bits then inserting new oracle as bits\n vaultVariables2 = (vaultVariables2 & X96) | (uint256(uint160(newOracle_)) << 96);\n\n emit LogUpdateOracle(newOracle_);\n }\n\n /// @notice updates the allowed rebalancer to `newRebalancer_`.\n function updateRebalancer(address newRebalancer_) public _updateExchangePrice _verifyCaller {\n if (newRebalancer_ == address(0)) revert FluidVaultError(ErrorTypes.VaultT1Admin__AddressZeroNotAllowed);\n\n rebalancer = newRebalancer_;\n\n emit LogUpdateRebalancer(newRebalancer_);\n }\n\n /// @notice sends any potentially stuck funds to Liquidity contract.\n /// @dev this contract never holds any funds as all operations send / receive funds from user <-> Liquidity.\n function rescueFunds(address token_) external _verifyCaller {\n if (token_ == NATIVE_TOKEN) {\n Address.sendValue(payable(IFluidVaultT1(address(this)).LIQUIDITY()), address(this).balance);\n } else {\n SafeERC20.safeTransfer(\n IERC20(token_),\n IFluidVaultT1(address(this)).LIQUIDITY(),\n IERC20(token_).balanceOf(address(this))\n );\n }\n\n emit LogRescueFunds(token_);\n }\n\n /// @notice absorbs accumulated dust debt\n /// @dev in decades if a lot of positions are 100% liquidated (aka absorbed) then dust debt can mount up\n /// which is basically sort of an extra revenue for the protocol.\n //\n // this function might never come in use that's why adding it in admin module\n function absorbDustDebt(uint[] memory nftIds_) public _verifyCaller {\n uint256 vaultVariables_ = vaultVariables;\n // re-entrancy check\n if (vaultVariables_ & 1 == 0) {\n // Updating on storage\n vaultVariables = vaultVariables_ | 1;\n } else {\n revert FluidVaultError(ErrorTypes.VaultT1__AlreadyEntered);\n }\n\n uint nftId_;\n uint posData_;\n int posTick_;\n uint tickId_;\n uint posCol_;\n uint posDebt_;\n uint posDustDebt_;\n uint tickData_;\n\n uint absorbedDustDebt_ = absorbedDustDebt;\n\n for (uint i = 0; i < nftIds_.length; ) {\n nftId_ = nftIds_[i];\n if (nftId_ == 0) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__NftIdShouldBeNonZero);\n }\n\n // user's position data\n posData_ = positionData[nftId_];\n\n if (posData_ == 0) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__NftNotOfThisVault);\n }\n\n posCol_ = (posData_ >> 45) & X64;\n // Converting big number into normal number\n posCol_ = (posCol_ >> 8) << (posCol_ & X8);\n\n posDustDebt_ = (posData_ >> 109) & X64;\n // Converting big number into normal number\n posDustDebt_ = (posDustDebt_ >> 8) << (posDustDebt_ & X8);\n\n if (posDustDebt_ == 0) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__DustDebtIsZero);\n }\n\n // borrow position (has collateral & debt)\n posTick_ = posData_ & 2 == 2 ? int((posData_ >> 2) & X19) : -int((posData_ >> 2) & X19);\n tickId_ = (posData_ >> 21) & X24;\n\n posDebt_ = (TickMath.getRatioAtTick(int24(posTick_)) * posCol_) >> 96;\n\n // Tick data from user's tick\n tickData_ = tickData[posTick_];\n\n // Checking if tick is liquidated OR if the total IDs of tick is greater than user's tick ID\n if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > tickId_)) {\n // User got liquidated\n (, posDebt_, , , ) = IFluidVaultT1(address(this)).fetchLatestPosition(\n posTick_,\n tickId_,\n posDebt_,\n tickData_\n );\n if (posDebt_ > 0) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__FinalDebtShouldBeZero);\n }\n // absorbing user's debt as it's 100% or almost 100% liquidated\n absorbedDustDebt_ = absorbedDustDebt_ + posDustDebt_;\n // making position as supply only\n positionData[nftId_] = 1;\n } else {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__NftNotLiquidated);\n }\n\n unchecked {\n i++;\n }\n }\n\n if (absorbedDustDebt_ == 0) {\n revert FluidVaultError(ErrorTypes.VaultT1Admin__AbsorbedDustDebtIsZero);\n }\n\n uint totalBorrow_ = (vaultVariables_ >> 146) & X64;\n // Converting big number into normal number\n totalBorrow_ = (totalBorrow_ >> 8) << (totalBorrow_ & X8);\n // note: by default dust debt is not added into total borrow but on 100% liquidation (aka absorb) dust debt equivalent\n // is removed from total borrow so adding it back again here\n totalBorrow_ = totalBorrow_ + absorbedDustDebt_;\n totalBorrow_ = BigMathMinified.toBigNumber(totalBorrow_, 56, 8, BigMathMinified.ROUND_UP);\n\n // adding absorbed dust debt to total borrow so it will get included in the next rebalancing.\n // there is some fuzziness here as when the position got fully liquidated (aka absorbed) the exchange price was different\n // than what it'll be now. The fuzziness which will be extremely small so we can ignore it\n // updating on storage\n vaultVariables =\n (vaultVariables_ & 0xfffffffffffc0000000000000003ffffffffffffffffffffffffffffffffffff) |\n (totalBorrow_ << 146);\n\n // updating on storage\n absorbedDustDebt = 0;\n\n emit LogAbsorbDustDebt(nftIds_, absorbedDustDebt_);\n }\n}\n"
},
"contracts/protocols/vault/vaultT1/common/variables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Variables {\n /***********************************|\n | Storage Variables |\n |__________________________________*/\n\n /// note: in all variables. For tick >= 0 are represented with bit as 1, tick < 0 are represented with bit as 0\n /// note: read all the variables through storageRead.sol\n\n /// note: vaultVariables contains vault variables which need regular updates through transactions\n /// First 1 bit => 0 => re-entrancy. If 0 then allow transaction to go, else throw.\n /// Next 1 bit => 1 => Is the current active branch liquidated? If true then check the branch's minima tick before creating a new position\n /// If the new tick is greater than minima tick then initialize a new branch, make that as current branch & do proper linking\n /// Next 1 bit => 2 => sign of topmost tick (0 -> negative; 1 -> positive)\n /// Next 19 bits => 3-21 => absolute value of topmost tick\n /// Next 30 bits => 22-51 => current branch ID\n /// Next 30 bits => 52-81 => total branch ID\n /// Next 64 bits => 82-145 => Total supply\n /// Next 64 bits => 146-209 => Total borrow\n /// Next 32 bits => 210-241 => Total positions\n uint256 internal vaultVariables;\n\n /// note: vaultVariables2 contains variables which do not update on every transaction. So mainly admin/auth set amount\n /// First 16 bits => 0-15 => supply rate magnifier; 10000 = 1x (Here 16 bits should be more than enough)\n /// Next 16 bits => 16-31 => borrow rate magnifier; 10000 = 1x (Here 16 bits should be more than enough)\n /// Next 10 bits => 32-41 => collateral factor. 800 = 0.8 = 80% (max precision of 0.1%)\n /// Next 10 bits => 42-51 => liquidation Threshold. 900 = 0.9 = 90% (max precision of 0.1%)\n /// Next 10 bits => 52-61 => liquidation Max Limit. 950 = 0.95 = 95% (max precision of 0.1%) (above this 100% liquidation can happen)\n /// Next 10 bits => 62-71 => withdraw gap. 100 = 0.1 = 10%. (max precision of 0.1%) (max 7 bits can also suffice for the requirement here of 0.1% to 10%). Needed to save some limits on withdrawals so liquidate can work seamlessly.\n /// Next 10 bits => 72-81 => liquidation penalty. 100 = 0.01 = 1%. (max precision of 0.01%) (max liquidation penantly can be 10.23%). Applies when tick is in between liquidation Threshold & liquidation Max Limit.\n /// Next 10 bits => 82-91 => borrow fee. 100 = 0.01 = 1%. (max precision of 0.01%) (max borrow fee can be 10.23%). Fees on borrow.\n /// Next 4 bits => 92-95 => empty\n /// Next 160 bits => 96-255 => Oracle address\n uint256 internal vaultVariables2;\n\n /// note: stores absorbed liquidity\n /// First 128 bits raw debt amount\n /// last 128 bits raw col amount\n uint256 internal absorbedLiquidity;\n\n /// position index => position data uint\n /// if the entire variable is 0 (meaning not initialized) at the start that means no position at all\n /// First 1 bit => 0 => position type (0 => borrow position; 1 => supply position)\n /// Next 1 bit => 1 => sign of user's tick (0 => negative; 1 => positive)\n /// Next 19 bits => 2-20 => absolute value of user's tick\n /// Next 24 bits => 21-44 => user's tick's id\n /// Below we are storing user's collateral & not debt, because the position can also be only collateral with no tick but it can never be only debt\n /// Next 64 bits => 45-108 => user's supply amount. Debt will be calculated through supply & ratio.\n /// Next 64 bits => 109-172 => user's dust debt amount. User's net debt = total debt - dust amount. Total debt is calculated through supply & ratio\n /// User won't pay any extra interest on dust debt & hence we will not show it as a debt on UI. For user's there's no dust.\n mapping(uint256 => uint256) internal positionData;\n\n /// Tick has debt only keeps data of non liquidated positions. liquidated tick's data stays in branch itself\n /// tick parent => uint (represents bool for 256 children)\n /// parent of (i)th tick:-\n /// if (i>=0) (i / 256);\n /// else ((i + 1) / 256) - 1\n /// first bit of the variable is the smallest tick & last bit is the biggest tick of that slot\n mapping(int256 => uint256) internal tickHasDebt;\n\n /// mapping tickId => tickData\n /// Tick related data. Total debt & other things\n /// First bit => 0 => If 1 then liquidated else not liquidated\n /// Next 24 bits => 1-24 => Total IDs. ID should start from 1.\n /// If not liquidated:\n /// Next 64 bits => 25-88 => raw debt\n /// If liquidated\n /// The below 3 things are of last ID. This is to be updated when user creates a new position\n /// Next 1 bit => 25 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated (100% liquidated)\n /// Next 30 bits => 26-55 => branch ID where this tick got liquidated\n /// Next 50 bits => 56-105 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)\n mapping(int256 => uint256) internal tickData;\n\n /// tick id => previous tick id liquidation data. ID starts from 1\n /// One tick ID contains 3 IDs of 80 bits in it, holding liquidation data of previously active but liquidated ticks\n /// 81 bits data below\n /// #### First 85 bits ####\n /// 1st bit => 0 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated\n /// Next 30 bits => 1-30 => branch ID where this tick got liquidated\n /// Next 50 bits => 31-80 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)\n /// #### Second 85 bits ####\n /// 85th bit => 85 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated\n /// Next 30 bits => 86-115 => branch ID where this tick got liquidated\n /// Next 50 bits => 116-165 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)\n /// #### Third 85 bits ####\n /// 170th bit => 170 => Is 100% liquidated? If this is 1 meaning it was above max tick when it got liquidated\n /// Next 30 bits => 171-200 => branch ID where this tick got liquidated\n /// Next 50 bits => 201-250 => debt factor 50 bits (35 bits coefficient | 15 bits expansion)\n mapping(int256 => mapping(uint256 => uint256)) internal tickId;\n\n /// mapping branchId => branchData\n /// First 2 bits => 0-1 => if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed\n /// merged means the branch is merged into it's base branch\n /// closed means all the users are 100% liquidated\n /// Next 1 bit => 2 => minima tick sign of this branch. Will only be there if any liquidation happened.\n /// Next 19 bits => 3-21 => minima tick of this branch. Will only be there if any liquidation happened.\n /// Next 30 bits => 22-51 => Partials of minima tick of branch this is connected to. 0 if master branch.\n /// Next 64 bits => 52-115 Debt liquidity at this branch. Similar to last's top tick data. Remaining debt will move here from tickData after first liquidation\n /// If not merged\n /// Next 50 bits => 116-165 => Debt factor or of this branch. (35 bits coefficient | 15 bits expansion)\n /// If merged\n /// Next 50 bits => 116-165 => Connection/adjustment debt factor of this branch with the next branch.\n /// If closed\n /// Next 50 bits => 116-165 => Debt factor as 0. As all the user's positions are now fully gone\n /// following values are present always again (merged / not merged / closed)\n /// Next 30 bits => 166-195 => Branch's ID with which this branch is connected. If 0 then that means this is the master branch\n /// Next 1 bit => 196 => sign of minima tick of branch this is connected to. 0 if master branch.\n /// Next 19 bits => 197-215 => minima tick of branch this is connected to. 0 if master branch.\n mapping(uint256 => uint256) internal branchData;\n\n /// Exchange prices are in 1e12\n /// First 64 bits => 0-63 => Liquidity's collateral token supply exchange price\n /// First 64 bits => 64-127 => Liquidity's debt token borrow exchange price\n /// First 64 bits => 128-191 => Vault's collateral token supply exchange price\n /// First 64 bits => 192-255 => Vault's debt token borrow exchange price\n uint256 internal rates;\n\n /// address of rebalancer\n address internal rebalancer;\n\n uint256 internal absorbedDustDebt;\n}\n"
},
"contracts/protocols/vault/vaultT1/coreModule/constantVariables.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultFactory } from \"../../interfaces/iVaultFactory.sol\";\nimport { IFluidLiquidity } from \"../../../../liquidity/interfaces/iLiquidity.sol\";\nimport { StorageRead } from \"../../../../libraries/storageRead.sol\";\n\nimport { Structs } from \"./structs.sol\";\n\ninterface TokenInterface {\n function decimals() external view returns (uint8);\n}\n\ncontract ConstantVariables is StorageRead, Structs {\n /***********************************|\n | Constant Variables |\n |__________________________________*/\n\n address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n /// @dev collateral token address\n address internal immutable SUPPLY_TOKEN;\n /// @dev borrow token address\n address internal immutable BORROW_TOKEN;\n\n /// @dev Token decimals. For example wETH is 18 decimals\n uint8 internal immutable SUPPLY_DECIMALS;\n /// @dev Token decimals. For example USDC is 6 decimals\n uint8 internal immutable BORROW_DECIMALS;\n\n /// @dev VaultT1 AdminModule implemenation address\n address internal immutable ADMIN_IMPLEMENTATION;\n\n /// @dev VaultT1 Secondary implemenation (main2.sol) address\n address internal immutable SECONDARY_IMPLEMENTATION;\n\n /// @dev liquidity proxy contract address\n IFluidLiquidity public immutable LIQUIDITY;\n\n /// @dev vault factory contract address\n IFluidVaultFactory public immutable VAULT_FACTORY;\n\n uint public immutable VAULT_ID;\n\n uint internal constant X8 = 0xff;\n uint internal constant X10 = 0x3ff;\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 X35 = 0x7ffffffff;\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\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n /// @dev slot ids in Liquidity contract. Helps in low gas fetch from liquidity contract by skipping delegate call\n bytes32 internal immutable LIQUIDITY_SUPPLY_EXCHANGE_PRICE_SLOT;\n bytes32 internal immutable LIQUIDITY_BORROW_EXCHANGE_PRICE_SLOT;\n bytes32 internal immutable LIQUIDITY_USER_SUPPLY_SLOT;\n bytes32 internal immutable LIQUIDITY_USER_BORROW_SLOT;\n\n /// @notice returns all Vault constants\n function constantsView() external view returns (ConstantViews memory constantsView_) {\n constantsView_.liquidity = address(LIQUIDITY);\n constantsView_.factory = address(VAULT_FACTORY);\n constantsView_.adminImplementation = ADMIN_IMPLEMENTATION;\n constantsView_.secondaryImplementation = SECONDARY_IMPLEMENTATION;\n constantsView_.supplyToken = SUPPLY_TOKEN;\n constantsView_.borrowToken = BORROW_TOKEN;\n constantsView_.supplyDecimals = SUPPLY_DECIMALS;\n constantsView_.borrowDecimals = BORROW_DECIMALS;\n constantsView_.vaultId = VAULT_ID;\n constantsView_.liquiditySupplyExchangePriceSlot = LIQUIDITY_SUPPLY_EXCHANGE_PRICE_SLOT;\n constantsView_.liquidityBorrowExchangePriceSlot = LIQUIDITY_BORROW_EXCHANGE_PRICE_SLOT;\n constantsView_.liquidityUserSupplySlot = LIQUIDITY_USER_SUPPLY_SLOT;\n constantsView_.liquidityUserBorrowSlot = LIQUIDITY_USER_BORROW_SLOT;\n }\n\n constructor(ConstantViews memory constants_) {\n LIQUIDITY = IFluidLiquidity(constants_.liquidity);\n VAULT_FACTORY = IFluidVaultFactory(constants_.factory);\n VAULT_ID = constants_.vaultId;\n\n SUPPLY_TOKEN = constants_.supplyToken;\n BORROW_TOKEN = constants_.borrowToken;\n SUPPLY_DECIMALS = constants_.supplyDecimals;\n BORROW_DECIMALS = constants_.borrowDecimals;\n\n // @dev those slots are calculated in the deploymentLogics / VaultFactory\n LIQUIDITY_SUPPLY_EXCHANGE_PRICE_SLOT = constants_.liquiditySupplyExchangePriceSlot;\n LIQUIDITY_BORROW_EXCHANGE_PRICE_SLOT = constants_.liquidityBorrowExchangePriceSlot;\n LIQUIDITY_USER_SUPPLY_SLOT = constants_.liquidityUserSupplySlot;\n LIQUIDITY_USER_BORROW_SLOT = constants_.liquidityUserBorrowSlot;\n\n ADMIN_IMPLEMENTATION = constants_.adminImplementation;\n SECONDARY_IMPLEMENTATION = constants_.secondaryImplementation;\n }\n}\n"
},
"contracts/protocols/vault/vaultT1/coreModule/events.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Events {\n /// @notice emitted when an operate() method is executed that changes collateral (`colAmt_`) / debt (debtAmt_`)\n /// amount for a `user_` position with `nftId_`. Receiver of any funds is the address `to_`.\n event LogOperate(address user_, uint256 nftId_, int256 colAmt_, int256 debtAmt_, address to_);\n\n /// @notice emitted when the exchange prices are updated in storage.\n event LogUpdateExchangePrice(uint256 supplyExPrice_, uint256 borrowExPrice_);\n\n /// @notice emitted when a liquidation has been executed.\n event LogLiquidate(address liquidator_, uint256 colAmt_, uint256 debtAmt_, address to_);\n\n /// @notice emitted when `absorb()` was executed to absorb bad debt.\n event LogAbsorb(uint colAbsorbedRaw_, uint debtAbsorbedRaw_);\n\n /// @notice emitted when a `rebalance()` has been executed, balancing out total supply / borrow between Vault\n /// and Fluid Liquidity pools.\n /// if `colAmt_` is positive then loss, meaning transfer from rebalancer address to vault and deposit.\n /// if `colAmt_` is negative then profit, meaning withdrawn from vault and sent to rebalancer address.\n /// if `debtAmt_` is positive then profit, meaning borrow from vault and sent to rebalancer address.\n /// if `debtAmt_` is negative then loss, meaning transfer from rebalancer address to vault and payback.\n event LogRebalance(int colAmt_, int debtAmt_);\n}\n"
},
"contracts/protocols/vault/vaultT1/coreModule/helpers.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"../common/variables.sol\";\nimport { ConstantVariables } from \"./constantVariables.sol\";\nimport { Events } from \"./events.sol\";\nimport { TickMath } from \"../../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../../libraries/bigMathMinified.sol\";\nimport { BigMathVault } from \"../../../../libraries/bigMathVault.sol\";\nimport { LiquidityCalcs } from \"../../../../libraries/liquidityCalcs.sol\";\n\nimport { ErrorTypes } from \"../../errorTypes.sol\";\nimport { Error } from \"../../error.sol\";\n\n/// @dev Fluid vault protocol helper methods. Mostly used for `operate()` and `liquidate()` methods of CoreModule.\nabstract contract Helpers is Variables, ConstantVariables, Events, Error {\n using BigMathMinified for uint256;\n using BigMathVault for uint256;\n\n /// @notice Calculates new vault exchange prices. Does not update values in storage.\n /// @param vaultVariables2_ exactly same as vaultVariables2 from storage\n /// @return liqSupplyExPrice_ latest liquidity's supply token supply exchange price\n /// @return liqBorrowExPrice_ latest liquidity's borrow token borrow exchange price\n /// @return vaultSupplyExPrice_ latest vault's supply token exchange price\n /// @return vaultBorrowExPrice_ latest vault's borrow token exchange price\n function updateExchangePrices(\n uint256 vaultVariables2_\n )\n public\n view\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n )\n {\n // Fetching last stored rates\n uint rates_ = rates;\n\n (liqSupplyExPrice_, ) = LiquidityCalcs.calcExchangePrices(\n LIQUIDITY.readFromStorage(LIQUIDITY_SUPPLY_EXCHANGE_PRICE_SLOT)\n );\n (, liqBorrowExPrice_) = LiquidityCalcs.calcExchangePrices(\n LIQUIDITY.readFromStorage(LIQUIDITY_BORROW_EXCHANGE_PRICE_SLOT)\n );\n\n uint256 oldLiqSupplyExPrice_ = (rates_ & X64);\n uint256 oldLiqBorrowExPrice_ = ((rates_ >> 64) & X64);\n if (liqSupplyExPrice_ < oldLiqSupplyExPrice_ || liqBorrowExPrice_ < oldLiqBorrowExPrice_) {\n // new liquidity exchange price is < than the old one. liquidity exchange price should only ever increase.\n // If not, something went wrong and avoid proceeding with unknown outcome.\n revert FluidVaultError(ErrorTypes.VaultT1__LiquidityExchangePriceUnexpected);\n }\n\n // liquidity Exchange Prices always increases in next block. Hence substraction with old will never be negative\n // uint64 * 1e18 is the max the number that could be\n unchecked {\n // Calculating increase in supply exchange price w.r.t last stored liquidity's exchange price\n // vaultSupplyExPrice_ => supplyIncreaseInPercent_\n vaultSupplyExPrice_ = ((((liqSupplyExPrice_ * 1e18) / oldLiqSupplyExPrice_) - 1e18) *\n (vaultVariables2_ & X16)) / 10000; // supply rate magnifier\n\n // Calculating increase in borrow exchange price w.r.t last stored liquidity's exchange price\n // vaultBorrowExPrice_ => borrowIncreaseInPercent_\n vaultBorrowExPrice_ = ((((liqBorrowExPrice_ * 1e18) / oldLiqBorrowExPrice_) - 1e18) *\n ((vaultVariables2_ >> 16) & X16)) / 10000; // borrow rate magnifier\n\n // It's extremely hard the exchange prices to overflow even in 100 years but if it does it's not an\n // issue here as we are not updating on storage\n // (rates_ >> 128) & X64) -> last stored vault's supply token exchange price\n vaultSupplyExPrice_ = (((rates_ >> 128) & X64) * (1e18 + vaultSupplyExPrice_)) / 1e18;\n // (rates_ >> 192) -> last stored vault's borrow token exchange price (no need to mask with & X64 as it is anyway max 64 bits)\n vaultBorrowExPrice_ = ((rates_ >> 192) * (1e18 + vaultBorrowExPrice_)) / 1e18;\n }\n }\n\n /// note admin module is also calling this function self call\n /// @dev updating exchange price on storage. Only need to update on storage when changing supply or borrow magnifier\n function updateExchangePricesOnStorage()\n public\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n )\n {\n (liqSupplyExPrice_, liqBorrowExPrice_, vaultSupplyExPrice_, vaultBorrowExPrice_) = updateExchangePrices(\n vaultVariables2\n );\n\n if (\n liqSupplyExPrice_ > X64 || liqBorrowExPrice_ > X64 || vaultSupplyExPrice_ > X64 || vaultBorrowExPrice_ > X64\n ) {\n revert FluidVaultError(ErrorTypes.VaultT1__ExchangePriceOverFlow);\n }\n\n // Updating in storage\n rates =\n liqSupplyExPrice_ |\n (liqBorrowExPrice_ << 64) |\n (vaultSupplyExPrice_ << 128) |\n (vaultBorrowExPrice_ << 192);\n\n emit LogUpdateExchangePrice(vaultSupplyExPrice_, vaultBorrowExPrice_);\n }\n\n /// @dev fetches new user's position after liquidation. The new liquidated position's debt is decreased by 0.01%\n /// to make sure that branch's liquidity never becomes 0 as if it would have gotten 0 then there will be multiple cases that we would need to tackle.\n /// @param positionTick_ position's tick when it was last updated through operate\n /// @param positionTickId_ position's tick Id. This stores the debt factor and branch to make the first connection\n /// @param positionRawDebt_ position's raw debt when it was last updated through operate\n /// @param tickData_ position's tick's tickData just for minor comparison to know if data is moved to tick Id or is still in tick data\n /// @return final tick position after all the liquidation\n /// @return final debt of position after all the liquidation\n /// @return positionRawCol_ final collateral of position after all the liquidation\n /// @return branchId_ final branch's ID where the position is at currently\n /// @return branchData_ final branch's data where the position is at currently\n function fetchLatestPosition(\n int256 positionTick_,\n uint256 positionTickId_,\n uint256 positionRawDebt_,\n uint256 tickData_\n )\n public\n view\n returns (\n int256, // positionTick_\n uint256, // positionRawDebt_\n uint256 positionRawCol_,\n uint256 branchId_,\n uint256 branchData_\n )\n {\n uint256 initialPositionRawDebt_ = positionRawDebt_;\n uint256 connectionFactor_;\n bool isFullyLiquidated_;\n\n // Checking if tick's total ID = user's tick ID\n if (((tickData_ >> 1) & X24) == positionTickId_) {\n // fetching from tick data itself\n isFullyLiquidated_ = ((tickData_ >> 25) & 1) == 1;\n branchId_ = (tickData_ >> 26) & X30;\n connectionFactor_ = (tickData_ >> 56) & X50;\n } else {\n {\n uint256 tickLiquidationData_;\n unchecked {\n // Fetching tick's liquidation data. One variable contains data of 3 IDs. Tick Id mapping is starting from 1.\n tickLiquidationData_ =\n tickId[positionTick_][(positionTickId_ + 2) / 3] >>\n (((positionTickId_ + 2) % 3) * 85);\n }\n\n isFullyLiquidated_ = (tickLiquidationData_ & 1) == 1;\n branchId_ = (tickLiquidationData_ >> 1) & X30;\n connectionFactor_ = (tickLiquidationData_ >> 31) & X50;\n }\n }\n\n // data of branch\n branchData_ = branchData[branchId_];\n\n if (isFullyLiquidated_) {\n positionTick_ = type(int).min;\n positionRawDebt_ = 0;\n } else {\n // Below information about connection debt factor\n // If branch is merged, Connection debt factor is used to multiply in order to get perfect liquidation of user\n // For example: Considering user was at the top.\n // In first branch, the user liquidated to debt factor 0.5 and then branch got merged (branching starting from 1)\n // In second branch, it got liquidated to 0.4 but when the above branch merged the debt factor on this branch was 0.6\n // Meaning on 1st branch, user got liquidated by 50% & on 2nd by 33.33%. So a total of 66.6%.\n // What we will set a connection factor will be 0.6/0.5 = 1.2\n // So now to get user's position, this is what we'll do:\n // finalDebt = (0.4 / (1 * 1.2)) * debtBeforeLiquidation\n // 0.4 is current active branch's minima debt factor\n // 1 is debt factor from where user started\n // 1.2 is connection factor which we found out through 0.6 / 0.5\n while ((branchData_ & 3) == 2) {\n // If true then the branch is merged\n\n // userTickDebtFactor * connectionDebtFactor *... connectionDebtFactor aka adjustmentDebtFactor\n connectionFactor_ = connectionFactor_.mulBigNumber(((branchData_ >> 116) & X50));\n if (connectionFactor_ == BigMathVault.MAX_MASK_DEBT_FACTOR) break; // user ~100% liquidated\n // Note we don't need updated branch data in case of 100% liquidated so saving gas for fetching it\n\n // Fetching new branch data\n branchId_ = (branchData_ >> 166) & X30; // Link to base branch of current branch\n branchData_ = branchData[branchId_];\n }\n // When the while loop breaks meaning the branch now has minima Debt Factor or is a closed branch;\n\n if (((branchData_ & 3) == 3) || (connectionFactor_ == BigMathVault.MAX_MASK_DEBT_FACTOR)) {\n // Branch got closed (or user liquidated ~100%). Hence make the user's position 0\n // Rare cases to get into this situation\n // Branch can get close often but once closed it's tricky that some user might come iterating through there\n // If a user comes then that user will be very mini user like some cents probably\n positionTick_ = type(int).min;\n positionRawDebt_ = 0;\n } else {\n // If branch is not merged, the main branch it's connected to then it'll have minima debt factor\n\n // position debt = debt * base branch minimaDebtFactor / connectionFactor\n positionRawDebt_ = positionRawDebt_.mulDivNormal(\n (branchData_ >> 116) & X50, // minimaDebtFactor\n connectionFactor_\n );\n\n unchecked {\n // Reducing user's liquidity by 0.01% if user got liquidated.\n // As this will make sure that the branch always have some debt even if all liquidated user left\n // This saves a lot more logics & consideration on Operate function\n // if we don't do this then we have to add logics related to closing the branch and factor connections accordingly.\n if (positionRawDebt_ > (initialPositionRawDebt_ / 100)) {\n positionRawDebt_ = (positionRawDebt_ * 9999) / 10000;\n } else {\n // if user debt reduced by more than 99% in liquidation then making user as fully liquidated\n positionRawDebt_ = 0;\n }\n }\n\n {\n if (positionRawDebt_ > 0) {\n // positionTick_ -> read minima tick of branch\n unchecked {\n positionTick_ = branchData_ & 4 == 4\n ? int((branchData_ >> 3) & X19)\n : -int((branchData_ >> 3) & X19);\n }\n // Calculating user's collateral\n uint256 ratioAtTick_ = TickMath.getRatioAtTick(int24(positionTick_));\n uint256 ratioOneLess_;\n unchecked {\n ratioOneLess_ = (ratioAtTick_ * 10000) / 10015;\n }\n // formula below for better readability:\n // length = ratioAtTick_ - ratioOneLess_\n // ratio = ratioOneLess_ + (length * positionPartials_) / X30\n // positionRawCol_ = (positionRawDebt_ * (1 << 96)) / ratio_\n positionRawCol_ =\n (positionRawDebt_ * TickMath.ZERO_TICK_SCALED_RATIO) /\n (ratioOneLess_ + ((ratioAtTick_ - ratioOneLess_) * ((branchData_ >> 22) & X30)) / X30);\n } else {\n positionTick_ = type(int).min;\n }\n }\n }\n }\n return (positionTick_, positionRawDebt_, positionRawCol_, branchId_, branchData_);\n }\n\n /// @dev sets `tick_` as having debt or no debt in storage `tickHasDebt` depending on `addOrRemove_`\n /// @param tick_ tick to add or remove from tickHasDebt\n /// @param addOrRemove_ if true then add else remove\n function _updateTickHasDebt(int tick_, bool addOrRemove_) internal {\n // Positive mapID_ starts from 0 & above and negative starts below 0.\n // tick 0 to 255 will have mapId_ as 0 while tick -256 to -1 will have mapId_ as -1.\n unchecked {\n int mapId_ = tick_ < 0 ? ((tick_ + 1) / 256) - 1 : tick_ / 256;\n\n // in case of removing:\n // (tick == 255) tickHasDebt[mapId_] - 1 << 255\n // (tick == 0) tickHasDebt[mapId_] - 1 << 0\n // (tick == -1) tickHasDebt[mapId_] - 1 << 255\n // (tick == -256) tickHasDebt[mapId_] - 1 << 0\n // in case of adding:\n // (tick == 255) tickHasDebt[mapId_] - 1 << 255\n // (tick == 0) tickHasDebt[mapId_] - 1 << 0\n // (tick == -1) tickHasDebt[mapId_] - 1 << 255\n // (tick == -256) tickHasDebt[mapId_] - 1 << 0\n uint position_ = uint(tick_ - (mapId_ * 256));\n\n tickHasDebt[mapId_] = addOrRemove_\n ? tickHasDebt[mapId_] | (1 << position_)\n : tickHasDebt[mapId_] & ~(1 << position_);\n }\n }\n\n /// @dev gets next perfect top tick (tick which is not liquidated)\n /// @param topTick_ current top tick which will no longer be top tick\n /// @return nextTick_ next top tick which will become the new top tick\n function _fetchNextTopTick(int topTick_) internal view returns (int nextTick_) {\n int mapId_;\n uint tickHasDebt_;\n\n unchecked {\n mapId_ = topTick_ < 0 ? ((topTick_ + 1) / 256) - 1 : topTick_ / 256;\n uint bitsToRemove_ = uint(-topTick_ + (mapId_ * 256 + 256));\n // Removing current top tick from tickHasDebt\n tickHasDebt_ = (tickHasDebt[mapId_] << bitsToRemove_) >> bitsToRemove_;\n\n // For last user remaining in vault there could be a lot of iterations in the while loop.\n // Chances of this to happen is extremely low (like ~0%)\n while (true) {\n if (tickHasDebt_ > 0) {\n nextTick_ = mapId_ * 256 + int(tickHasDebt_.mostSignificantBit()) - 1;\n break;\n }\n\n // Reducing mapId_ by 1 in every loop; if it reaches to -129 then no filled tick exist, meaning it's the last tick\n if (--mapId_ == -129) {\n nextTick_ = type(int).min;\n break;\n }\n\n tickHasDebt_ = tickHasDebt[mapId_];\n }\n }\n }\n\n /// @dev adding debt to a particular tick\n /// @param totalColRaw_ total raw collateral of position\n /// @param netDebtRaw_ net raw debt (total debt - dust debt)\n /// @return tick_ tick where the debt is being added\n /// @return tickId_ tick current id\n /// @return userRawDebt_ user's total raw debt\n /// @return rawDust_ dust debt used for adjustment\n function _addDebtToTickWrite(\n uint256 totalColRaw_,\n uint256 netDebtRaw_ // debtRaw - dust\n ) internal returns (int256 tick_, uint256 tickId_, uint256 userRawDebt_, uint256 rawDust_) {\n if (netDebtRaw_ < 10000) {\n // thrown if user's debt is too low\n revert FluidVaultError(ErrorTypes.VaultT1__UserDebtTooLow);\n }\n // tick_ & ratio_ returned from library is round down. Hence increasing it by 1 and increasing ratio by 1 tick.\n uint ratio_ = (netDebtRaw_ * TickMath.ZERO_TICK_SCALED_RATIO) / totalColRaw_;\n (tick_, ratio_) = TickMath.getTickAtRatio(ratio_);\n unchecked {\n ++tick_;\n ratio_ = (ratio_ * 10015) / 10000;\n }\n userRawDebt_ = (ratio_ * totalColRaw_) >> 96;\n rawDust_ = userRawDebt_ - netDebtRaw_;\n\n // Current state of tick\n uint256 tickData_ = tickData[tick_];\n tickId_ = (tickData_ >> 1) & X24;\n\n uint tickNewDebt_;\n if (tickId_ > 0 && tickData_ & 1 == 0) {\n // Current debt in the tick\n uint256 tickExistingRawDebt_ = (tickData_ >> 25) & X64;\n tickExistingRawDebt_ = (tickExistingRawDebt_ >> 8) << (tickExistingRawDebt_ & X8);\n\n // Tick's already initialized and not liquidated. Hence simply add the debt\n tickNewDebt_ = tickExistingRawDebt_ + userRawDebt_;\n if (tickExistingRawDebt_ == 0) {\n // Adding tick into tickHasDebt\n _updateTickHasDebt(tick_, true);\n }\n } else {\n // Liquidation happened or tick getting initialized for the very first time.\n if (tickId_ > 0) {\n // Meaning a liquidation happened. Hence move the data to tickID\n unchecked {\n uint tickMap_ = (tickId_ + 2) / 3;\n // Adding 2 in ID so we can get right mapping ID. For example for ID 1, 2 & 3 mapping should be 1 and so on..\n // For example shift for id 1 should be 0, for id 2 should be 85, for id 3 it should be 170 and so on..\n tickId[tick_][tickMap_] =\n tickId[tick_][tickMap_] |\n ((tickData_ >> 25) << (((tickId_ + 2) % 3) * 85));\n }\n }\n // Increasing total ID by one\n unchecked {\n ++tickId_;\n }\n tickNewDebt_ = userRawDebt_;\n\n // Adding tick into tickHasDebt\n _updateTickHasDebt(tick_, true);\n }\n if (tickNewDebt_ < 10000) {\n // thrown if tick's debt/liquidity is too low\n revert FluidVaultError(ErrorTypes.VaultT1__TickDebtTooLow);\n }\n tickData[tick_] = (tickId_ << 1) | (tickNewDebt_.toBigNumber(56, 8, BigMathMinified.ROUND_DOWN) << 25);\n }\n\n /// @dev sets new top tick. If it comes to this function then that means current top tick is perfect tick.\n /// if next top tick is liquidated then unitializes the current non liquidated branch and make the liquidated branch as current branch\n /// @param topTick_ current top tick\n /// @param vaultVariables_ vaultVariables of storage but with newer updates\n /// @return newVaultVariables_ newVaultVariables_ updated vault variable internally to this function\n /// @return newTopTick_ new top tick\n function _setNewTopTick(\n int topTick_,\n uint vaultVariables_\n ) internal returns (uint newVaultVariables_, int newTopTick_) {\n // This function considers that the current top tick was not liquidated\n // Overall flow of function:\n // if new top tick liquidated (aka base branch's minima tick) -> Close the current branch and make base branch as current branch\n // if new top tick not liquidated -> update things in current branch.\n // if new top tick is not liquidated and same tick exist in base branch then tick is considered as not liquidated.\n\n uint branchId_ = (vaultVariables_ >> 22) & X30; // branch id of current branch\n\n uint256 branchData_ = branchData[branchId_];\n int256 baseBranchMinimaTick_;\n if ((branchData_ >> 196) & 1 == 1) {\n baseBranchMinimaTick_ = int((branchData_ >> 197) & X19);\n } else {\n unchecked {\n baseBranchMinimaTick_ = -int((branchData_ >> 197) & X19);\n }\n if (baseBranchMinimaTick_ == 0) {\n // meaning the current branch is the master branch\n baseBranchMinimaTick_ = type(int).min;\n }\n }\n\n // Returns type(int).min if no top tick exist\n int nextTopTickNotLiquidated_ = _fetchNextTopTick(topTick_);\n\n newTopTick_ = baseBranchMinimaTick_ > nextTopTickNotLiquidated_\n ? baseBranchMinimaTick_\n : nextTopTickNotLiquidated_;\n\n if (newTopTick_ == type(int).min) {\n // if this happens that means this was the last user of the vault :(\n vaultVariables_ = vaultVariables_ & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00001;\n } else if (newTopTick_ == nextTopTickNotLiquidated_) {\n // New top tick exist in current non liquidated branch\n if (newTopTick_ < 0) {\n unchecked {\n vaultVariables_ =\n (vaultVariables_ & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00001) |\n (uint(-newTopTick_) << 3);\n }\n } else {\n vaultVariables_ =\n (vaultVariables_ & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00001) |\n 4 | // setting top tick as positive\n (uint(newTopTick_) << 3);\n }\n } else {\n // if this happens that means base branch exists & is the next top tick\n // Remove current non liquidated branch as active.\n // Not deleting here as it's going to get initialize again whenever a new top tick comes\n branchData[branchId_] = 0;\n // Inserting liquidated branch's minima tick\n unchecked {\n vaultVariables_ =\n (vaultVariables_ & 0xfffffffffffffffffffffffffffffffffffffffffffc00000000000000000001) |\n 2 | // Setting top tick as liquidated\n (((branchData_ >> 196) & X20) << 2) | // new current top tick = base branch minima tick\n (((branchData_ >> 166) & X30) << 22) | // new current branch id = base branch id\n ((branchId_ - 1) << 52); // reduce total branch id by 1\n }\n }\n\n newVaultVariables_ = vaultVariables_;\n }\n\n constructor(ConstantViews memory constants_) ConstantVariables(constants_) {}\n}\n"
},
"contracts/protocols/vault/vaultT1/coreModule/structs.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Structs {\n // structs are used to mitigate Stack too deep errors\n\n struct OperateMemoryVars {\n // ## User's position before update ##\n uint oldColRaw;\n uint oldNetDebtRaw; // total debt - dust debt\n int oldTick;\n // ## User's position after update ##\n uint colRaw;\n uint debtRaw;\n uint dustDebtRaw;\n int tick;\n uint tickId;\n // others\n uint256 vaultVariables2;\n uint256 branchId;\n int256 topTick;\n uint liquidityExPrice;\n uint supplyExPrice;\n uint borrowExPrice;\n uint branchData;\n // user's supply slot data in liquidity\n uint userSupplyLiquidityData;\n }\n\n struct BranchData {\n uint id;\n uint data;\n uint ratio;\n uint debtFactor;\n int minimaTick;\n uint baseBranchData;\n }\n\n struct TickData {\n int tick;\n uint data;\n uint ratio;\n uint ratioOneLess;\n uint length;\n uint currentRatio; // current tick is ratio with partials.\n uint partials;\n }\n\n // note: All the below token amounts are in raw form.\n struct CurrentLiquidity {\n uint256 debtRemaining; // Debt remaining to liquidate\n uint256 debt; // Current liquidatable debt before reaching next check point\n uint256 col; // Calculate using debt & ratioCurrent\n uint256 colPerDebt; // How much collateral to liquidate per unit of Debt\n uint256 totalDebtLiq; // Total debt liquidated till now\n uint256 totalColLiq; // Total collateral liquidated till now\n int tick; // Current tick to liquidate\n uint ratio; // Current ratio to liquidate\n uint tickStatus; // if 1 then it's a perfect tick, if 2 that means it's a liquidated tick\n int refTick; // ref tick to liquidate\n uint refRatio; // ratio at ref tick\n uint refTickStatus; // if 1 then it's a perfect tick, if 2 that means it's a liquidated tick, if 3 that means it's a liquidation threshold\n }\n\n struct TickHasDebt {\n int tick; // current tick\n int nextTick; // next tick with liquidity\n int mapId; // mapping ID of tickHasDebt\n uint bitsToRemove; // liquidity to remove till tick_ so we can search for next tick\n uint tickHasDebt; // getting tickHasDebt_ from tickHasDebt[mapId_]\n uint mostSigBit; // most significant bit in tickHasDebt_ to get the next tick\n }\n\n struct LiquidateMemoryVars {\n uint256 vaultVariables2;\n int liquidationTick;\n int maxTick;\n uint256 supplyExPrice;\n uint256 borrowExPrice;\n }\n\n struct AbsorbMemoryVariables {\n uint256 debtAbsorbed;\n uint256 colAbsorbed;\n int256 startingTick;\n uint256 mostSigBit;\n }\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 struct RebalanceMemoryVariables {\n uint256 liqSupplyExPrice;\n uint256 liqBorrowExPrice;\n uint256 vaultSupplyExPrice;\n uint256 vaultBorrowExPrice;\n }\n}\n"
},
"contracts/reserve/interfaces/iReserveContract.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidity } from \"../../liquidity/interfaces/iLiquidity.sol\";\n\ninterface IFluidReserveContract {\n function isRebalancer(address user) external returns (bool);\n\n function initialize(\n address[] memory _auths,\n address[] memory _rebalancers,\n IFluidLiquidity liquidity_,\n address owner_\n ) external;\n\n function rebalanceFToken(address protocol_) external;\n\n function rebalanceVault(address protocol_) external;\n\n function transferFunds(address token_) external;\n\n function getProtocolTokens(address protocol_) external;\n\n function updateAuth(address auth_, bool isAuth_) external;\n\n function updateRebalancer(address rebalancer_, bool isRebalancer_) external;\n\n function approve(address[] memory protocols_, address[] memory tokens_, uint256[] memory amounts_) external;\n\n function revoke(address[] memory protocols_, address[] memory tokens_) external;\n}\n"
},
"solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnershipTransferred(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnershipTransferred(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function transferOwnership(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnershipTransferred(msg.sender, newOwner);\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
}
}
}